prototype

发布时间 2023-05-22 17:56:33作者: pangqianjin

1. prototype和__proto__

function Foo() {
    ...
}

Foo.prototype.constructor === Foo; // true

let foo = new Foo();
foo.constructor === Foo; // true

例如,当声明一个函数Foo的时候,会默认给这个函数的prototype添加一个constructor属性,并且指向Foo函数本身。

但是,函数Foo的实例对象foo,它的身上是没有constuctor这个属性的,这里foo是通过原型找到该属性的,即foo.proto.constructor,其实foo.__proto__就是指向了Foo.prototype,即foo.__proto__ === Foo.prototype; // true

foo.constructor === Foo; // true
foo.hasOwnProperty('constructor'); // false
foo.__proto__.hasOwnProperty('constructor'); // true

Foo.hasOwnProperty('constructor'); // false
Foo.prototype.hasOwnProperty('constructor'); // true

// 因为
foo.__proto__ === Foo.prototype; // true

2. __proto__和prototype的关系

  • __proto__ : JS每个对象内部都隐含了一个__proto__属性,用来指向它的原型对象,即xxx.prototype。
    例如对象a:let a = {name: "example"}
    image
  • prototype : 与__proto__不同的是,这个属性只有函数才有。并且添加到prototype上的属性和方法在所有实例中都是共享的。譬如Foo.prototype,可以看到Foo.prototype中也有__proto__属性,指向它的原型对象。

3. 使用prototype实现继承

通过原型很容易实现对象间的继承,JS中继承是通过委托机制实现的。最常用的一种方式是通过Object.create(..)方法。

function Foo() {
    this.name = "Foo";
}

Foo.prototype.sayName = function () {
    return "This is " + this.name;
}

function Bar() {
    this.name = "Bar";
}

// 让Bar继承Foo
Bar.prototype = Object.create(Foo.prototype);

let bar = new Bar();
bar.sayName();  // This is Bar

// 此时 bar.__proto__ -> Bar.prototype -> Foo.prototype -> Object.prototype -> null
bar.__proto__ === Foo.prototype; // true
Object.getPrototypeOf(bar) === Bar.prototype; // true

通过Object.create(..)方法,让Bar的原型链指向Foo的原型实现继承效果。如图所示:
image

4. 对象关联

如果要使两个对象关联起来,比如让对象bar关联对象foo, 同样使用Object.create()方法

function Foo() {
    this.name = "Foo";
}

Foo.prototype.sayName = function () {
    return "This is " + this.name;
}

function Bar() {
    this.name = "Bar";
}

// 让Bar继承Foo
Bar.prototype = Object.create(Foo.prototype);

let bar = new Bar();
bar.sayName();  // This is Bar

// 此时,bar.__proto__ -> foo -> Foo.prototype -> Object.prototype -> null
Object.getPrototypeOf(bar) === Bar.prototype; // false
Object.getPrototypeOf(bar) === foo; // true

这里仅仅是两个对象的关联!因此不仅可以调用Foo.prototype原型上的方法,也可以调用foo对象上的方法。如图
image

5. 获取原型链

  • 直接通过 foo.__proto__
  • 通过 Object.getPrototypeOf(foo)