构造函数或构造器具备prototype属性 对象具备__proto__属性 这就是以前学习的原型
若是构造函数或对象A A的原型指向构造函数或对象B B的原型在指向构造函数或对象C 以此类推 最终的构造函数或对象的原型指向Object的原型 由此造成一条链状结构 被称之为原型链
按照上述的描述 在B中定义的属性或方法 能够直接在A中使用并不须要定义 这就是继承 它容许每一个对象来访问其原型链上的任何属性或方法。
原型链是ECMAScript标准中指定的默认实现继承方式。app
// 原型链 function A(){ this.a = 'a'; } // 经过构造函数建立对象 var a = new A(); function B(){ this.b = 'b'; } // 将B的原型指向对象a B.prototype = a; // 经过构造函数建立对象 var b = new B(); console.log(b.b);// b console.log(b.a);// a function C(){ this.c = 'c'; } // 将C的原型指向对象b C.prototype = b; // 经过构造函数建立对象 var c = new C(); console.log(c.c);// c console.log(c.b);// b console.log(c.a);// a
处于对效率的考虑,尽可能的将属性和方法添加到原型上。
1.不要为继承关系单首创建对象。
2.尽可能减小运行时的方法搜索。函数
// 原型链 function A(){ // 将自有属性改写为原型属性 // this.a = 'a'; } A.prototype.a = 'a'; function B(){ // this.b = 'b'; } // 将B的原型指向 B.prototype = A.prototype; B.prototype.b = 'b'; /*B.prototype = { b : 'b' }*/ function C(){ this.c = 'c'; } // 将C的原型指向 C.prototype = B.prototype; var c = new C(); console.log(c.c);// c console.log(c.b); console.log(c.a);// a
原型链虽然很强大,用他能够实现JavaScript中的继承,但同时也存在着一些问题。
1.原型链实际上实在多个构造函数或对象之间共享属性和方法。
2.常见子类的对象时,不能向父级的构造函数传递任何参数。
在实际开发中不多会单独使用原型链。学习
// 原型链 function A(){ // 将自有属性改写为原型属性 // this.a = 'a'; } A.prototype.a = 'a'; function B(){ // this.b = 'b'; } // 将B的原型指向 B.prototype = A.prototype; B.prototype.b = 'b'; function C(){ // this.c = 'c'; } // 将C的原型指向 C.prototype = B.prototype; C.prototype.c = 'c'; var c = new C(); console.log(c.c);// c console.log(c.b);// b console.log(c.a);// a var a = new A(); console.log(a.a); console.log(a.b); console.log(a.c); var b = new B(); console.log(b.a); console.log(b.b); console.log(b.c);
所谓的原型式继承,就是定义一个函数,该函数中建立一个临时性 的构造函数,将做为参数传入的对象,做为这个构造函数的原型,左后返回这个构造函数的实例对象。this
/* 定义一个函数 - 用于实现对象之间的继承 * 参数 * obj - 表示继承关系中的父级对象 * prop - 对象格式,表示继承关系中的子级对象的属性和方法 */ function fn(obj, porp){ // 定义一个临时的构造函数 function Fun(){ // 遍历对象的属性和方法 for (var attrName in porp) { // var attrValue = porp[attrName]; this[attrName] = porp[attrName]; } } // 将函数的参数做为构造函数的原型 Fun.prototype = obj; // 将构造函数建立的对象进行返回 return new Fun(); } var obj = { name : '张无忌' } // 调用函数 var result = fn(obj, { age : 18, sayMe : function(){ console.log('this is function'); } }); console.log(result.age); result.sayMe();
注意;原型式继承具备与原型链相同的问题。prototype
不管是原型链仍是原型式继承,都具备相同的问题。想要解决这样的问题的话,能够借助构造函数(也能够叫作伪造对象或经典继承)。
这种方式实现很是简单,就是在子对象的构造函数中调用父对象的构造函数,具体能够经过调用apply()和call()方法实现。
apply()和call()方法容许传递指定某个对形象的 this。对于继承来讲,能够实现子对象构造函数中调用父对象的构造函数时,将子对象的this和父对象的this绑定在一块儿。code
// 定义父级对象的构造函数 function Parent(){ this.parent = 'parent'; } // 定义子级对象的构造函数 function Child(){ // 调用父级对象的构造函数 -> 使用apply()或call()方法 Parent.call(this); this.child = 'child'; } // 建立子级对象 var child = new Child(); console.log(child);
组合继承,也佳做为经典继承,指的是将原型链或原型式继承和借助构造.函数的技术组合在一块儿,发挥两者长处的一种继承方式。
1.使用原型链或原型式继承实现对原型的属性和方法的继承。
2.经过借助构造函数实现对实例对象的属性和继承。
这样既经过在原型定义方法实现了函数的重用,又保证每一个对象都有本身的专有属性。对象
function Parent(){ // 构造函数的自有属性 this.name = '张无忌'; } // 构造函数的原型属性 Parent.prototype.age = 18; function Child(){ // 继承父级构造函数中的自有属性 Parent.call(this); this.job = '教主'; } // 继承父级构造函数中的原型属性 Child.prototype = Parent.prototype; var child = new Child(); console.log(child.job); console.log(child.age); console.log(child.name);