1.原型
每个函数都有一个 prototype 的属性,称之为原型,因为 prototype 是个对象,又称为原型对象。
作用:
-
存放一些属性和方法。
-
在 JS 中实现继承。
比如:
const arr = new Array(1, 2, 3);
arr.reverse();
arr.sort();
为什么创建一个数组以后就可以使用 reverse(),sort()或者其他方法?
因为 Array 构造函数也是一个函数,而函数就会有一个原型对象 Array.prototype,而 JS 在这个原型对象上挂载了很多的方法,所以在使用构造函数 Array 创建实例 arr 的时候,arr 就可以使用 Array。prototype 上的这些方法。
至于为什么实例 arr 可以使用构造函数 Array 原型对象 prototype 上的方法,就要牵扯到原型链。
2.原型链
每个对象都有一个属性叫 __proto__。
作用:
-
这个属性会指向它的构造函数的原型对象。
const arr = new Array(1, 2, 3);
arr.reverse();
arr.sort();
console.log(arr.__proto__ === Array.prototype); // true
前面说为什么实例 arr 可以使用构造函数 Array 原型对象 prototype 上的方法,就是因为有这个__proto__ 存在。当访问一个对象
的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会通过它的__proto__
属性,找到它的构造函数
的原型对象
,如果还没有找到就会再在其构造函数
的prototype
的__proto__
中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链
。
注意:如果通过实例对象
的__proto__
属性赋值,则会改变其构造函数
的原型对象
,从而被所有实例所共享。
构造函数 Person 创建的实例 person,person 的 __proto__ 属性指向 Person.prototype,而 Person.prototype 也是一个对象,Person.prototyp. __proto__ 就会指向 Person 的构造函数也就是 Object 的原型对象 Object.prototype,这就是说,person 可以通过 __proto__ 去访问 Person.prototype上的属性,如果 Person.prototype 上面没有想要的东西,就再去更高一层的 Object.prototype 上面找,直到找到 null 没有为止,原型链的尽头是 null。
3.原型链的尽头
所有的原型对象
的 __proto__
属性都是指向 function Object
的原型对象
。 而function Object
的原型对象
是不存在__proto__
这个属性的,它指向了null
。我们就得知了原型链
的尽头是null
。