简单理解就是原型组成的链,对象的__proto__它的是原型,而原型也是一个对象,也有__proto__属性,原型的__proto__又是原型的原型,就这样能够一直经过__proto__想上找,这就是原型链,当向上找找到Object的原型的时候,这条原型链就算到头了。app
全部原型链属性传递方向 (某个属性在本对象中找不到时候,会到原型链上去找): 先找对象 自己属性 =》构造函数的prototype中属性 =》Object.prototype中的属性=》null (结束)函数
function Person(){ this.name = name; this.age = age; } Person.prototype.talk = function(){ console.log("hello"); } let ming = new Person("ming",24);//ming === {name:"ming",age:24} ming.talk(); // ming中没有talk这个属性,就会经过__proto__到到原型链中去找,ming.__proto__ === Person.prototype。 //因为ming.__proto__也就是 Person.prototype 也是一个对象,因此 ming.__proto__.__proto__ === Object.prototype。(若是ming.__proto__中没有找到talk属性会继续向上找ming.__proto__.__proto__ ,直到找到最顶层null)
经过一个构造函数建立出来的多个实例,若是都要添加一个方法,给每一个实例去添加并非一个明智的选择。这时就该用上原型了。this
在实例的原型上添加一个方法,这个原型的全部实例便都有了这个方法。
例子:给全部的function 添加一个 before属性 和 after属性prototype
Function.prototype.before = function(beforeFn){ let functionObj = this; return function (){ beforeFn.apply(this,arguments); functionObj.apply(this,arguments); } } Function.prototype.after = function(afterFn){ let functionObj = this; return function (){ functionObj.apply(this,arguments); afterFn(); } } function test(){ console.log('this is a test function!'); } let test1 = test.before(function(){ console.log(arguments); console.log('before'); }).after(()=>{ console.log('after'); }); test1();
//例子1 function Animal (){ this.speak = function(){}//第一种,直接将方法写入构造函数中 } Animal.prototype.speak = function(){};//第二种将方法写到原型链中 let dog1 = new Animal(); let dog2 = new Animal(); console.log (dog1.speak === dog2.speak) //第一种,返回false,第二种返回true
总结:假如将方法写入构造函数中,每一次实例化都会去建立这样一个功能彻底相同的函数,会很是耗费内存,而写入原型链中只会建立一次,因此建议一般状况下将实例方法写到原型链中。code