前言html
JS做为面向对象的弱类型语言,继承也是其很是强大的特性之一。那么如何在JS中实现继承呢?让咱们拭目以待。函数
既然要实现继承,那么首先咱们得有一个父类,代码以下:性能
// 定义一个动物类 function Animal (name) { // 属性 this.name = name || 'Animal'; // 实例方法 this.sleep = function(){ console.log(this.name + '正在睡觉!'); } } // 原型方法 Animal.prototype.eat = function(food) { console.log(this.name + '正在吃:' + food); };
核心: 将父类的实例做为子类的原型this
function Cat(){ } Cat.prototype = new Animal(); Cat.prototype.name = 'cat'; // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.eat('fish')); console.log(cat.sleep()); console.log(cat instanceof Animal); //true console.log(cat instanceof Cat); //true
特色:spa
缺点:prototype
new Animal()
这样的语句以后执行,不能放到构造器中推荐指数:★★(三、4两大体命缺陷)code
2017-8-17 10:21:43补充:感谢 MMHS 指出。缺点1中描述有误:能够在Cat构造函数中,为Cat实例增长实例属性。若是要新增原型属性和方法,则必须放在new Animal()
这样的语句以后执行。htm
核心:使用父类的构造函数来加强子类实例,等因而复制父类的实例属性给子类(没用到原型)对象
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // false console.log(cat instanceof Cat); // true
特色:blog
缺点:
推荐指数:★★(缺点3)
核心:为父类实例添加新特性,做为子类实例返回
function Cat(name){ var instance = new Animal(); instance.name = name || 'Tom'; return instance; } // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // false
特色:
new 子类()
仍是子类()
,返回的对象具备相同的效果缺点:
推荐指数:★★
function Cat(name){ var animal = new Animal(); for(var p in animal){ Cat.prototype[p] = animal[p]; } Cat.prototype.name = name || 'Tom'; } // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // false console.log(cat instanceof Cat); // true
特色:
缺点:
推荐指数:★(缺点1)
核心:经过调用父类构造,继承父类的属性并保留传参的优势,而后经过将父类实例做为子类原型,实现函数复用
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } Cat.prototype = new Animal(); // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // true
特色:
缺点:
推荐指数:★★★★(仅仅多消耗了一点内存)
核心:经过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } (function(){ // 建立一个没有实例方法的类 var Super = function(){}; Super.prototype = Animal.prototype; //将实例做为子类的原型 Cat.prototype = new Super(); })(); // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); //true
特色:
缺点:
推荐指数:★★★★(实现复杂,扣掉一颗星)
示例一:
function Animal (name) { // 属性 this.name = name || 'Animal'; // 实例方法 this.sleep = function(){ console.log(this.name + '正在睡觉!'); } //实例引用属性 this.features = []; } function Cat(name){ } Cat.prototype = new Animal(); var tom = new Cat('Tom'); var kissy = new Cat('Kissy'); console.log(tom.name); // "Animal" console.log(kissy.name); // "Animal" console.log(tom.features); // [] console.log(kissy.features); // [] tom.name = 'Tom-New Name'; tom.features.push('eat'); //针对父类实例值类型成员的更改,不影响 console.log(tom.name); // "Tom-New Name" console.log(kissy.name); // "Animal" //针对父类实例引用类型成员的更改,会经过影响其余子类实例 console.log(tom.features); // ['eat'] console.log(kissy.features); // ['eat']
缘由分析: 关键点:属性查找过程 执行tom.features.push,首先找tom对象的实例属性(找不到), 那么去原型对象中找,也就是Animal的实例。发现有,那么就直接在这个对象的 features属性中插入值。 在console.log(kissy.features); 的时候。同上,kissy实例上没有,那么去原型上找。 恰好原型上有,就直接返回,可是注意,这个原型对象中features属性值已经变化了。摘自---http://www.cnblogs.com/humin/p/4556820.html