JavaScript 中的原型和原型链对于我来说实在是太难了,为了这一篇文章,我大概准备了一个月,理解起来属实有些难度,不仅要懂
__proto__
和prototype
之间的关系,还要知道如何通过原型链实现继续,实现new
的关键字。能力有限,这篇先理解一下原型和原型链,一步一步实现new
和继承
先上一张图,原型的指向都在这张图里面,我会一点一点的拆解出来
prototype
每个函数都会创建一个prototype属性,这个属性是一个对象,包含应该由特定引用类型的实例 共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处 是,在它上面定义的属性和方法可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以 直接赋值给它们的原型。这个属性会指向函数的原型对象:
const Foo = function(name) {
this.name = name
}
Foo.prototype.age = 18;
const f1 = new Foo("Lius");
console.log(f1.name) // Lius
console.log(f1.age) // 18
理解一下:
- 构造函数 Foo
- 实例对象 Foo
- 在构造函数里面定义了
name
属性 - 在 Foo 的 prototype 属性上面定义了 age 属性 并赋值为 18
上述例子中函数的 prototype 指向了一个对象,而这个对象正是调用构造函数时创建的实例的原型,也就是通过new 关键字创建出来的 f1 实例对象;
拆分上图:
constructor
无论何时,只要创建一个函数,就会按照特定的规则为这个函数创建一个prototype 属性(指向
原型对象)。默认情况下,所有原型对象自动获得一个名为constructor 的属性,指回与之关联的构
造函数。即 Foo.prototype.constructor === Foo
拆分上图:
__ proto __
这是每个对象(除null外)都会有的属性,叫做__proto__,这个属性会指向该对象的原型。即: f1.__proto__===Foo.prototype
注意他们的区别 __proto__
存在于实例对象上面, prototype
存在于构造函数
拆分上图:
到此为止, JS中的原型和原型链可以算是说完了,但是可以继续深究下去,根据最开始的图可以看到
var Foo = function()
Foo 也是有原型的。
Foo() 的原型
定义的函数的原型是 Function
, 也就是说 Foo()
是 Function
的实例对象,那么函数定义可以写成 var Foo = new Function()
。其实并没有必要去深究这么多,我们只需要知道在JS中原型的指向就可以了,根据上图还可以看出 Function 是 Object 的原型实例,同样 Object 也是 Function 的原型实例。形成了一个闭环,这不是我们关注的重点,重点是要根据JS的原型来解释 new
关键字和如何通过原型来实现继承。
请关注下篇 new 和 继承