一、原型链图示
Foo为构造函数,foo是Foo的实例化对象,Foo.prototype是原型对象。
__proto__属性是对象特有的,prototype属性是函数特有的。
二、原型链的查找机制
js规定,所有的(实例)对象都有自己的原型对象(Foo.prototype)。
查找的顺序是:对象的原型 ==> 原型的原型 ==> 原型的原型的原型 ==> ... ==> Object.prototype ==> null
如果一层一层查找,所有的对象的原型都会找到Object.prototype,所有的对象都继承了Object.prototype中的属性和方法。 如toString()
三、原型链的作用
定制所有实例对象共享的属性和方法。
读取属性和方法的规则:
- js引擎会先寻找对象本身的属性和方法,如果找不到那就去原型对象上去找,如果还是找不到,就去原型的原型去找,如果直到最顶层Object.prototype还是找不到,就会返回undefined。
- 如果对象和它的原型都定制了同名的属性,那么优先读取对象自身的属性。
function Foo() {};
Foo.prototype.name = 'mm';
var f = new Foo();
console.log(f.age); // undefined
f.name = 'gg'
console.log(f.name); // gg
console.log(Foo.prototype.name); // mm
四、constructor属性
constructor表示原型对象和构造函数之间的关联关系。
现在我们改造一个自定义的数组对象,就可以通过prototype实现。
我们知道原型对象的constructor是指向构造函数本身的,因此当我们改变了原型对象的指向时,要把constructor改回自定义的构造函数。以免出现引用问题。
function myArray() {};
myArray.prototype = Array.prototype; // 把数组的属性和方法赋值给myArray
myArray.prototype.constructor = myArray; // 把构造器指向myArray 不改的话指向Array
var arr = new myArray();
arr.push(1,2,3);
console.log(myArray.prototype.constructor === myArray); // true
五、构造函数、原型对象、实例对象之间的关系
实例对象的__proto__属性指向了原型对象。
原型对象的constructor属性指向了构造函数。
实例对象的constructor属性继承自原型对象的constructor,所以同样指向了构造函数。
(说白了还是那张原型链的图。。。)