一.原型链
原型链的基本思想是利用原型让一个引用类型继承另外一个引用类型的属性和方法。每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的指针。若是:咱们让原型对象A等于另外一个类型B的实例,那么原型对象A就会有一个指针指向B的原型对象,相应的B的原型对象中保存着指向其构造函数的指针。假如B的原型对象又是另外一个类型的实例,那么上述的关系依旧成立,如此层层递进,就构成了实例与原型的链条数组
一、默认的原型
前面的例子中展现的原型链少了一环,全部引用类型默认都继承了Object,而这个继承也是经过原型链实现的。所以默认的原型都包含一个内部指针,指向Object.prototype,这也正是全部自定义类型会继承toString()、ValueOf()等默认方法的根本缘由。换句话说Object.prototype就是原型链的末端。
二、肯定原型和实例的关系
经过两种方式能够肯定原型和实例之间的关系,第一种是使用instanceOf操做符,第二种是使用isPrototypeOf()方法。
实例 instanceOf 原型链 中出现过的构造函数,都会返回true
JavaScript中isPrototypeOf函数方法是返回一个布尔值,指出对象是否存在于另外一个对象的原型链中。使用方法:app
object1.isPrototypeOf(object2)函数
三、谨慎地定义方法
子类型有时候须要覆盖超类型中的某个方法,或者须要添加超类型中不存在的莫个方法,注意:给原型添加方法的代码必定要放在替换原型的语句以后。
当经过Child的实例调用getParentValue()时,调用的是这个从新定义过的方法,可是经过Parent的实例调用getParentValue()时,调用的仍是原来的方法。
格外须要注意的是:必需要在Parent的实例替换原型以后,再定义这两个方法。
还有一点须要特别注意的是:经过原型链实现继承时,不能使用对象字面量建立原型方法,由于这样作会重写原型链。this
四、原型链的问题
原型链很强大,能够利用它来实现继承,可是也有一些问题,主要的问题仍是包含引用类型值的原型属性会被全部实例共享。所以咱们在构造函数中定义实例属性。可是在经过原型来实现继承时,原型对象其实变成了另外一个类型的实例。因而原先定义在构造函数中的实例属性变成了原型属性了。spa
2.借用构造函数
为了解决原型中包含引用类型值带来的一些问题,引入了借用构造函数的技术。这种技术的基础思想是:在子类型构造函数的内部调用超类型构造函数。
Parent.call(this)在新建立的Child实例的环境下调用了Parent构造函数。在新建立的Child实例环境下调用Parent构造函数。这样,就在新的Child对象上,此处的kid1和kid2对象上执行Parent()函数中定义的对象初始化代码。这样,每一个Child实例就都会具备本身的friends属性的副本了。
借用构造函数的方式能够在子类型的构造函数中向超类型构造函数传递参数
为了确保子类型的熟悉不会被父类的构造函数重写,能够在调用父类构造函数以后,再添加子类型的属性。
构造函数的问题:
构造函数模式的问题,在于方法都在构造函数中定义,函数复用无从谈起,所以,借用构造函数的模式也不多单独使用。prototype
3.组合继承
组合继承指的是将原型链和借用构造函数的技术组合在一块,从而发挥两者之长。即:使用原型链实现对原型属性和方法的继承,而经过借用构造函数来实现对实例属性的继承。
Person构造函数定义了两个属性:name和friends。Person的原型定义了一个方法sayName()。Child构造函数在调用Parent构造函数时,传入了name参数,紧接着又定义了本身的属性age。而后将Person的实例赋值给Child的原型,而后又在该原型上定义了方法sayAge().这样,两个不一样的Child实例既分别拥有本身的属性,包括引用类型的属性,又可使用相同的方法了。
组合继承避免了原型链和构造函数的缺陷,融合了他们的有点,成为JavaScript中最经常使用的继承模式。并且,instanceOf和isPropertyOf()也可以识别基于组合继承建立的对象。指针
4.对象冒充
对象冒充包括三种:临时属性方式、call()及apply()方式
1.临时属性方式: code
1 function A(x){ 2 this.x=x; this.say = function(){ alert('My name is '+this.name); } 3 } 4 function B(x,y){ 5 this.tmpObj=A; 6 this.tmpObj(x); 7 delete this.tmpObj; 8 this.id = id; this.showId = function(){ alert('Good morning,Sir,My work number is '+this.id); } 9 }
var simon = new B('Simon',9527);
simon.say();
simon.showId();
/**/第五、六、7行:建立临时属性tmpObj引用构造函数A,而后在B内部执行,执行完后删除。当在B内部执行了 this.x=x后(这里的this是B的对象),B固然就拥有了x属性,固然B的x属性和A的x属性二者是独立,因此并不能算严格的继承。第五、六、7行有更简单的实现,就是经过call(apply)方法:A.call(this,x);对象
2.call()/apply()方式:实质上是改变了this指针的指向、blog
1 function Person(name){ 2 this.name = name; 3 this.say = function(){ 4 alert('My name is '+this.name); 5 } 6 } 7 function F2E(name,id){ 8 Person.call(this,name); //apply()方式改为Person.apply(this,[name]); 9 this.id = id; 10 this.showId = function(){ 11 alert('Good morning,Sir,My work number is '+this.id); 12 } 13 } 14 var simon = new F2E('Simon',9527); 15 simon.say(); 16 simon.showId();
/**/call和apply均可以实现继承,惟一的一点参数不一样,func.call(func1,var1,var2,var3)对应的apply写法为:func.apply(func1,[var1,var2,var3])。区别在于 call 的第二个参数能够是任意类型,而apply的第二个参数必须是数组,也能够是arguments。
经过对象冒充的方式,没法继承经过prototype方式定义的变量和方法:
5.原型式继承
基本想法:借助原型能够基于已有的对象建立新对象,同时还没必要须所以建立自定义的类型。
原型式继承的思想可用如下函数来讲明:
1 function object(o) { 2 function F(){} 3 F.prototype = o; 4 return new F(); 5 } 6 例子: 7 var person = { 8 name:"EvanChen", 9 friends:["Shelby","Court","Van"]; 10 }; 11 var anotherPerson = object(person); 12 anotherPerson.name = "Greg"; 13 anotherPerson.friends.push("Rob"); 14 var yetAnotherPerson = object(person); 15 yetAnotherPerson.name = "Linda"; 16 yetAnotherPerson.friends.push("Barbie"); 17 console.log(person.friends);//"Shelby","Court","Van","Rob","Barbie"
ECMAScript5经过新增Object.create()方法规范化了原型式继承,这个方法接收两个参数:一个用做新对象原型的对象和一个做为新对象定义额外属性的对象。
var person = { name:"EvanChen", friends:["Shelby","Court","Van"]; }; var anotherPerson = Object.create(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = Object.create(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); console.log(person.friends);//"Shelby","Court","Van","Rob","Barbie"
6.寄生式继承
基本思想:建立一个仅用于封装继承过程的函数,该函数在内部以某种方式来加强对象,最后再像真正是它作了全部工做同样返回对象。
例子:
1 function createAnother(original) { 2 var clone = object(original); 3 clone.sayHi = function () { 4 alert("hi"); 5 }; 6 return clone; 7 } 8 var person = { 9 name:"EvanChen", 10 friends:["Shelby","Court","Van"]; 11 }; 12 var anotherPerson = createAnother(person); 13 anotherPerson.sayHi();///"hi"
7.寄生组合式继承
基本思想:经过借用函数来继承属性,经过原型链的混成形式来继承方法
其基本模型以下所示:
function inheritProperty(subType, superType) { var prototype = object(superType.prototype);//建立对象 prototype.constructor = subType;//加强对象 subType.prototype = prototype;//指定对象 } 例子: function SuperType(name){ this.name = name; this.colors = ["red","blue","green"]; } SuperType.prototype.sayName = function (){ alert(this.name); }; function SubType(name,age){ SuperType.call(this,name); this.age = age; } inheritProperty(SubType,SuperType); SubType.prototype.sayAge = function() { alert(this.age); }