一、原型(属性)__proto__
每个实例对象(obj)的私有属性,在ECMAScript中规定obj.[[Prototype]]符号表示实例对象的原型。但早期并没有统一规范,所以大部分浏览器自己实现了该私有属性,多以__proto__的方式进行访问,该属性指向实例对象obj的构造函数的原型对象(prototype)。
二、原型对象 prototype
每个构造函数(本身也是对象)有一个prototype属性,表示它的原型对象。其本身作为一个对象也具有一个原型属性__proto__。同时构造函数的原型对象有一个constructor属性,它指向构造函数本身。看上去有点绕,引用冴羽大佬博客里的一张图片作展示,就看的很清楚了。
三、原型链 prototype chain
向上述这样,一个实例对象-->构造函数的原型对象-->构造函数的原型对象的构造函数原型对象-->...-->null,就构成了一条原型链。根据定义,null没有原型(属性),作为这个原型链中的最后一个环节。举个例子
const a = {a: 1} // a ---> Object.prototype ---> null
console.log(a.__proto__ === Object.prototype) // true
console.log(Object.getPrototypeOf(a) === Object.prototype) // true
console.log(a.__proto__.__proto__ === null) // true
console.log(Object.getPrototypeOf(Object.getPrototypeOf(a)) === null) // true
四、ES6对原型的实现
在ES6中,__proto__这一私有属性规范化,通过Object.getPrototypeOf(obj)和Object.setPrototypeOf(obj)来访问。
五、原型继承
Object.create(obj) 新建一个对象实例,这个对象实例的原型(属性)指向obj。举个例子
const b = Object.create(a) // b ---> a ---> Object.prototype ---> null
console.log(b.__proto__ === a) // true
console.log(Object.getPrototypeOf(b) === a) // true
console.log(b.__proto__.__proto__ === Object.prototype) // true
console.log(Object.getPrototypeOf(Object.getPrototypeOf(b)) === Object.prototype) // true
console.log(b.__proto__.__proto__.__proto__ === null) // true
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(b))) === null) // true
六、总结
JS一切都是对象,JS只有这一种“结构”,每个对象都有一个私有属性称之为原型(__proto__),它指向该对象的构造函数的原型对象(prototype),而原型对象也有原型(__proto__),一直到最后指向null,null没有原型,就到了原型链的尽头。