咱们知道任何一个函数都存在一个prototype属性,他是个对象,这个对象 咱们就叫他原型对象
这个原型对象自己也自带两个属性:constructor 和 protoapp
constructor: 这个属性是指向建立此对象的构造函数的引用,构造函数的实例化对象,也能够经过constuctor属性来访问构造它的那个函数_proto_: 这个属性指向建立此对象的构造函数的prototype原型对象的引用函数
例子: //个人家族姓莫 function Parent(){ this.name = 'mo' } //我家族是音乐世家 Parent.prototype.work = function(){ return 'musicing' } //爸妈生了我 var me = new Parent() //我也要唱歌 console.log(me.work()) //=>musicing //爸爸妈妈又生了二胎 var myBrother = new Parent() //他也会唱歌 console.log(myBrother.work()) //=>musicing //证实我两是不是亲生的 console.log(me.work() === myBrother.work()) //=>true 解释一波: me 和 myBrother 是构造函数Parent()new出来的的一个实例,me 和 myBrother 都有一个隐式属性_proto_,引用Parent() 的prototype属性来获得继承
在访问 me 的 work 方法时,找不到, 就会顺着_protp_属性往上在构造函数的prototype找,找到了就中止,没找到继续往上到Object.prototype找,再没找到就到null了,天然也找不到就只能返回undifined,这种链式的引用就是原型链,经过原型链实现继承仍是很方便的this
万一原型链断链呢?
缘由:若是对 构造函数 或者 原型链 修改一些方法或者属性的时候,致使函数的constructor不等于建立它的构造函数,那就会断链prototype
若是 先实例再经过 字面量添加或修改,那么后新定义的方法就对先继承的方法或属性就会不在生效,就会断链,这是由于字面量来修改原型时,constructor发生了改变,也就是说该函数指向的建立该函数的构造函数发生了改变,字面量默认的constructor的值是Object(),因此为了不断链,尽可能不要使用字面量从新赋值,修改code
例子: //建立一个构造函数Car function Car(){ this.brand = '大奔'; } //大奔 80万 Car.prototype.price = '80'; //我来买一个大奔 先实例 var benCar1 = new Car(); console.log(benCar1.price) //=>80 //我但愿个人大奔 带有翅膀的 能飞 Car.prototype = { hasWing: true, hasFlying: function(){ console.log('flying...') } } var benCar = new Car() (1) 正常状况下 console.log(benCar1.brand,benCar1.price,benCar1.hasWing,benCar1.hasFlying,benCar1.constructor) //=> 大奔 80 undefined undefined ƒ Car(){} (2)字面量添加属性方法时 console.log(benCar.brand,benCar.price,benCar.hasWing,benCar.hasFlying,benCar.constructor) //=> 大奔 undefined true ƒ (){} ƒ Object() { [native code] }
(1) 原型链继承对象
原型链继承是经过 new实例化构造函数 赋给子类的原型, 其实实例的子类自己是彻底的空对象,全部的属性方法都须要去原型链上找。
例子: function Grandpa(){ this.name = 'mo' } Grandpa.prototype.work = function(){ return 'musicing' } function Parent(){ } Parent.prototype = new Grandpa() var me = new Parent() console.log(me.work()) //=>musicing 我找啊找啊原来是Grandpa会musicing var myBrother = new Parent() console.log(myBrother.work()) //=>musicing console.log(me.work() === myBrother.work()) //=>true
(2) 构造函数继承继承
构造函数继承 经过apply去调用父类的构造函数,达到继承父类的实例属性,对,只能继承属性,要想继承方法 采用寄生组合继承
例子 function Grandpa(firstname){ this.name = 'mo ' + firstname } Grandpa.prototype.work = function(){ return 'musicing' } function Parent(firstname){ Grandpa.apply(this, arguments) } Parent.prototype = new Grandpa() var me = new Parent('alice') console.log(me.work()) //=>musicing var myBrother = new Parent('bob') console.log(myBrother.work()) //=>musicing console.log(me.work() === myBrother.work()) //=>true console.log(me.name, myBrother.name,me.name === myBrother.name)//=>mo alice ,mo bob ,false
(3) 寄生组合继承内存
寄生组合继承是咱们常常要用到的,组合了原型和构造函数,结合Object.create(obj),方法对传入的对象进行浅拷贝,这样能够实现对实例属性和原型属性分别进行继承
浅拷贝:仅仅是指向被拷贝的内存地址,若是原地址中对象被改变了,那么浅拷贝出来的对象也会相应改变ci
例子: // 寄生组合继承 function Grandpa(firstname){ this.name = 'mo ' + firstname } Grandpa.prototype.work = function(){ return 'musicing' } function Parent(firstname){ Grandpa.apply(this, arguments) } // Parent.prototype = new Grandpa() //改为 Parent.prototype = Object.create(Grandpa.prototype); // Object.create()将父级对象的属性和方法进行引用 Parent.prototype.constructor = Parent; //将该函数的construnctor指向parent构造函数 console.log(Parent.prototype) var me = new Parent('alice') var myBrother = new Parent('bob') console.log(me.work() === myBrother.work()) //=>true console.log(me.name, myBrother.name,me.name === myBrother.name)//=>mo alice ,mo bob ,false
好了,有时间还会补充...原型链