Skip to content

原型链

概念

prototype(原型)是函数的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。 __proto__(原型链)是对象的一个属性,它指向该对象的原型。通过该对象可以访问原型的属性和方法。

从属关系

prototype(原型)是函数 Function 的一个属性,它指向一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。 __proto__(原型链)是对象 Object 的一个属性,它指向该对象的原型。通过该对象可以访问原型的属性和方法。 对象的__proto__保存着对象的构造函数的 prototype。

Function.prototype === Function.__proto__ // true Object.prototype === Object.__proto__ // true Object.__proto__ === Function.prototype // true Object.__proto__ === Function.__proto__ // true

判断实例对象是否有某个属性,可以使用 hasOwnProperty 方法。 test.hasOwnProperty('name') 判断实例对象原型链上是否有某个属性,可以使用 in 运算符。 test.name in test

constructor -> 实例化对象的构造函数

通过原型判断类型

在 JavaScript 中,我们通常使用typeofinstanceof运算符来判断一个变量的类型。然而,这两种方式都有它们的局限性。typeof只能判断出基本类型,而instanceof只能判断出对象的类型,并且它依赖于原型链,如果原型链被修改,那么结果可能就不准确了。

如果你想通过原型来判断类型,你可以使用Object.prototype.toString.call()方法。这个方法会返回一个表示该对象的字符串,格式为[object Type],其中Type是对象的类型。这种方法可以准确判断出所有类型的值,包括nullundefined

例如:

javascript
let num = 1;
let str = "hello";
let arr = [1, 2, 3];
let obj = {};
let fun = function () {};
let date = new Date();
let reg = /test/g;
let err = new Error();

console.log(Object.prototype.toString.call(num)); // "[object Number]"
console.log(Object.prototype.toString.call(str)); // "[object String]"
console.log(Object.prototype.toString.call(arr)); // "[object Array]"
console.log(Object.prototype.toString.call(obj)); // "[object Object]"
console.log(Object.prototype.toString.call(fun)); // "[object Function]"
console.log(Object.prototype.toString.call(date)); // "[object Date]"
console.log(Object.prototype.toString.call(reg)); // "[object RegExp]"
console.log(Object.prototype.toString.call(err)); // "[object Error]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"

这样,你就可以通过原型来判断 JavaScript 中的类型了。

继承与共享属性

在 JavaScript 中,原型(prototype)是一种非常强大的机制,它用于实现继承和共享属性。以下是原型的一些主要用途:

  1. 实现继承:在 JavaScript 中,你可以使用原型来实现继承。这是通过将一个对象的原型设置为另一个对象来实现的。这样,当你尝试访问一个对象的属性时,如果这个对象本身没有这个属性,那么 JavaScript 就会去它的原型对象中查找。

    javascript
    function Person(name) {
      this.name = name;
    }
    
    Person.prototype.sayHello = function () {
      console.log("Hello, I'm " + this.name);
    };
    
    var alice = new Person("Alice");
    alice.sayHello(); // "Hello, I'm Alice"

    在这个例子中,sayHello方法是定义在Person的原型上的,所有的Person实例都可以访问到这个方法。

  2. 共享属性:原型可以用来共享属性。当你在一个对象的原型上定义一个属性时,所有的这个对象的实例都可以访问这个属性。

    javascript
    function Team(name) {
      this.name = name;
    }
    
    Team.prototype.members = [];
    
    var team1 = new Team("Team 1");
    var team2 = new Team("Team 2");
    
    team1.members.push("Alice");
    console.log(team2.members); // ["Alice"]

    在这个例子中,members属性是定义在Team的原型上的,所以所有的Team实例都共享这个属性。

  3. 扩展内置类型:你可以使用原型来扩展 JavaScript 的内置类型,比如ArrayString等。这是通过在内置类型的原型上添加方法来实现的。

    javascript
    Array.prototype.first = function () {
      return this[0];
    };
    
    var arr = [1, 2, 3];
    console.log(arr.first()); // 1

    在这个例子中,我们在Array的原型上添加了一个first方法,所有的数组都可以使用这个方法。

请注意,虽然原型是一个非常强大的工具,但是也需要谨慎使用。在原型上添加属性或方法会影响所有的实例,如果不小心,可能会导致一些难以预料的问题。

hancenter808@outlook.com