Keep moving just play & have fun

前端重要知识点总结

2018-03-21
May

阅读:

Web

基础


__proto__和prototype的区别和关系

在了解原型之前,必须先弄清几个概念:

对象

js中的对象分为两种:

  • 普通对象

    • 普通对象:有__proto__属性(指向其构造函数的原型对象),没有prototype属性。
    • 原型对象:(Person.prototype 原型对象),原型对象还有一个constructor属性(指向构造函数对象)
  • 函数对象

    • 通过new Function()创建的都是函数对象。函数对象拥有__proto__、prototype属性。Function, Object, Array, Date, String, 自定义函数
  • 原型对象

    每创建一个函数都会有一个prototype属性,这个属性是一个指针,指向一个对象。原型对象包含特定类型的所有实例共享的属性和方法。

来看看一张比较容易看得懂的图,深度理解对象的原型:

  1. 在JS里,万物皆对象。

方法(Function)是对象,方法的原型(Function.prototype)是对象。

对象具有__proto__属性,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这样保证了实例能够访问在构造函数原型中定义的属性和方法。

  1. 方法(Function)

方法也是对象,除了和其他对象一样拥有__proto__属性之外,还有自己特有的属性—-原型属性(prototype)。这个属性是一个指针,指向一个对象(及原型对象),这个对象包含了所有实例共享的属性和方法。原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。

再来看看上面那张图:

  1. Foo() 构造函数

构造函数Foo()的原型属性Foo.prototype指向原型对象,在原型对象里有共有的属性和方法,所有构造函数声明的实例(这里是f1, f2)都可以共享这个方法。

  1. 原型对象Foo.prototype

Foo.prototype保存这实例共享的方法,有一个指回构造函数的指针constructor.

  1. 对象实例f1, f2

f1, f2是对象Foo的实例,对象的实例有__proto__属性,指向对象的构造函数的原型对象,这样就可以访问原型对象的所有方法了。

BTW,Foo()构造函数除了是方法,也是对象(函数对象),也有__proto__属性,那么这个__proto__指向谁呢?

函数的__proto__属性指向函数的构造函数的原型对象。函数的构造函数就是Function,因此,函数的__proto__属性指向Function.prototype.

除了Foo(), Function()和Object()都是一样的道理。

原型对象也是对象,那它(比如,Foo.prototype,Function.prototype)的__proto__属性指向谁呢?

同理,指向它的构造函数的原型对象,这里是Object.prototype。

最后,Object.prototype的__proto__属性指向null。

总结:

1. 对象有属性__proto__,它指向对象的构造函数的原型对象。

2. 函数有prototype属性,函数的prototype属性指向函数的原型对象,因为函数也是对象,函数的__proto__同样指向函数的构造函数的原型对象。

原型链

首先,看一张图了解一下实例、原型对象和构造函数之间的关系。

从上图可以看出,每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针(constructor),而实例对象都包含一个指向原型对象的__prototype__内部指针。

如果让原型对象等于另一个类型的实例,那么此时的原型对象将包含一个指向另一个原型对象的(proto)指针,另一个原型对象也包含指向另一个构造函数的指针(constructor)。加入

另一个原型又是另一个类型的实例。。。。。。这就构成了实例与原型的链条。也就是原型链。

看图:

举例说明:

function Animal() {
    this.type = 'animal';
}

Animal.prototype.getType = function() {
    return this.type;
}

function Dog() {
    this.name ='wangwang';
}

Dog.prototype = new Animal();

var wangcai = new Dog();

wangcai.getType(); // 'animal'
// 原型链的关系:
wangcai.__proto__ === Dog.prototype
Dog.prototype.__proto__ === Animal.prototype
Animal.prototye.__proto__ === Object.prototype
Object.prototype.__proto__ === null

js中实现继承主要依靠原型链查找

原型继承(prototype-based inheritance)的步骤大概是这样:

  1. 每一个函数F都有一个原型对象(prototype)F.prototype

  2. 每一个函数都可以通过new 关键字来创建一个类构造函数,new F()会产一个一个对象O

  3. 在调用对象的某个属性和方法时,比如O.xxx, 首先会查找这个对象自身有没有这个属性或者方法,没有就会去(这个对象的构造函数的原型对象中查找),也就是找O的构造函数F的原型对象F.prototype.xxx。

  4. 原型对象F.prototype.xxx也是一个对象,查找F.prototype.xxx会重复步骤3.


上一篇 AMD&CMD

下一篇 js设计模式

Comments

Content