标签:
讨论了原型和原型链我们不得不了解一下继承,js是基于对象的,虽然不会像真正的面向对象编程语言通过类实现继承,但可以通过其他方法实现继承,并且方法很多,现在就来看一下吧!
1.原型链方式
从上一章原型链的讲解中也能了解到原型链是可以实现继承的
1 function SuperType() { 2 this.num = [12, 13, 14]; 3 } 4 function SubType() {} 5 SubType.prototype = new SuperType(); 6 7 var instance1 = new SubType(); 8 instance1.num.push(15); 9 console.log(instance1.num); //[12, 13, 14, 15] 10 11 var instance2 = new SubType(); 12 console.log(instance2.num); //[12, 13, 14, 15]
这样是实现继承了,可是创建的其中一个实例其他实例也会改变,这绝不是我们想要的。所以其他方式~
2.借用构造函数(也叫伪经典或经典继承)
function SuperType() { this.num = [12, 13, 14]; } function SubType() { SuperType.call(this); // } var instance1 = new SubType(); instance1.num.push(15); console.log(instance1.num); //[12, 13, 14, 15] var instance2 = new SubType(); console.log(instance2.num); //[12, 13, 14]
这种方式是实现了上述的要求,可是方法是在构造函数中创建的,实例不能访问构造函数里的方法也不能拥有自己独特的方法。所以,又有一种更好的方法~
3.组合继承(伪经典继承)
最常用的继承方式,将原型链与借用构造函数结合
思想:通过使用原型链实现原型上的属性和方法继承,借用构造函数实现实例属性的继承
1 function SuperType(num) { 2 this.num = num; 3 } 4 SuperType.prototype.sayNum = function() { 5 console.log("SuperType" + this.num); 6 }; 7 function SubType(num, age) { 8 SuperType.call(this, num); //继承属性 9 this.age = age; 10 } 11 SubType.prototype.sayNum = function() { 12 console.log("SubType" + this.num); 13 }; 14 15 SubType.prototype.sayAge = function() { 16 console.log("sayAge" + this.age); 17 } 18 19 //继承方法 20 var instance1 = new SubType([12,13,14]); 21 instance1.num.push(15); 22 console.log(instance1.num); //[12, 13, 14, 15] 23 24 var instance2 = new SubType([12,13], 25); 25 console.log(instance2.num); //[12, 13] 26 console.log(instance2.sayAge()); //25
虽然组合式继承在js很受欢迎,但还是存在缺点,就是调用两次超类型构造函数,一次是在创建子类型原型时,另一次是在子类型的构造函数内部。那么,解
决这个问题就是用寄生组合式实现继承。不过,在说寄生组合式继承之前,先了解原型式继承以及寄生式继承有助于更好的了解寄生组合式继承。
4.原型式继承
1 function object(proto) { // 2 function F() {} 3 F.prototype = proto; 4 return new F(); 5 } 6 7 var person = { 8 name: ‘nana‘, 9 friends: [‘lili‘, ‘xuexue‘] 10 }; 11 12 var anotherPerson = object(person); // 13 anotherPerson.friends.push(‘jing‘); 14 var yetAnotherPerson = object(person); 15 anotherPerson.friends.push(‘tian‘); 16 console.log(person.friends);
这种方法在ECMAScript5中增添了Object.create()方法,与object方法相同,但是只有主流浏览器支持因此需要兼容。
兼容方法
1 if(!Object.create) { 2 Object.create = function(proto) { 3 function F() {} 4 F.prototype = proto; 5 return new F(); 6 }; 7 }
5.寄生式继承
1 function object(proto) { 2 function F() {} 3 F.prototype = proto; 4 return new F(); 5 } 6 function createObject(original) { // 7 var clone = object(original); 8 clone.sayhi = function() { 9 console.log("sayhi"); 10 } 11 return clone; 12 } 13 var person = { 14 name: ‘nana‘, 15 friends: [‘lili‘, ‘xuexue‘] 16 }; 17 var anotherPerson = createObject(person); 18 anotherPerson.sayhi();
前面object()函数不是必须的,任何可以返回新对象的都可以。
6.寄生组合式
1 function SuperType(num) { 2 this.num = num; 3 } 4 SuperType.prototype.sayNum = function() { 5 console.log(this.num); 6 }; 7 8 function SubType(num, age) { 9 SuperType.call(this, num); //继承属性 10 this.age = age; 11 } 12 13 if(!Object.create) { 14 Object.create = function(proto) { 15 function F() {} 16 F.prototype = proto; 17 return new F(); 18 }; 19 } 20 21 SubType.prototype = Object.create(SuperType); 22 SubType.constructor = SubType; 23 24 SubType.prototype.sayAge = function() { 25 console.log(this.age); 26 }; 27 var instance = new SubType([1, 2, 3], 20); 28 instance.sayAge();
这种方法也是现在实现继承方法中最完美的,也是最理想的。
那么,怎么判断属性是来自实例还是原型呢?
1 function hasPrototypePrototype(object, name) { 2 return !object.hasOwnProperty(name) && (name in object); 3 }
参数object为对象,name为属性,
name in object 判断属性是否存在于对象上,
object.hasOwnProperty(name)当返回true时,证name属性存在于实例中,返回false为原型中。
标签:
原文地址:http://www.cnblogs.com/nalixueblog/p/4480185.html