如何处理javascript中的继承关系,这个是比较重要的一环。说到继承,先来个小测试:求方法实现 f(6).num(1),结果等于6。
想到方法了吗?不如先来看一段代码:
var $ = function(selector){ return new $.prototype.init(selector) }; $.prototype = { constructor:$, init:function(selector){ this.length = selector }, product(val){ return val * this.length }, length:0 }; $.prototype.init.prototype = $.prototype; //关键 console.log($(6).product(1));
如果研究过jQuery源码,应该了解,这就是jQuery面向对象的基本思路,关键点在继承,子类继承父类的原型属性和方法。jQuery的巧妙在于:子类同时也是父类的一个原型方法。
1、利用 call、apply 继承
function Food(i){ this.name = i; } Food.prototype.use = "eat"; function Fish(x,y,z){ Food.apply(this,[z]); //Food.call(this,z) x可省略 this.color = x; this.weight = y } var fish = new Fish("golden","1kg","Salmon"); console.log(fish.name,fish.use);//fish.use:undefined 说明不能继承父类原型的属性和方法
缺点:
不能继承父类原型的属性和方法。
2、原型链继承
function Food(i){ this.name = i; } Food.prototype.use = "eat"; var food = new Food("Cod"); function Fish(x,y){ this.color = x; this.weight = y } Fish.prototype = new Food("Salmon"); console.log(Fish.prototype.constructor === Food);//true 此时,构造函数已经指向了Food Fish.prototype.constructor = Fish; //因为“Fish.prototype = new Food("Salmon");”将构造函数指向了Food,需要再次指回Fish var fish = new Fish("golden","1kg"); console.log(fish.name,fish.use);
缺点:
· 继承时,要再次生成父类实例,耗费内存;
· 子类要添加属性和方法,只能在“Fish.prototype = new Food("Salmon");”后面。
3、直接继承prototype
function Food(i){ this.name = i } function Fish(x,y){ this.color = x; this.weight = y } Fish.prototype = Food.prototype; //相当于完全删除了prototype 对象原先的值 console.log(Fish.prototype.constructor === Food); //true,同样,构造函数已经指向了Food Fish.prototype.constructor = Fish; console.log(Food.prototype.constructor === Fish); //true true 问题所在:父类和子类的构造函数,都指向了同一个对象:Fish var fish = new Fish("golden","1kg"); console.log(fish.name,fish.color);//fish.name:undefined 说明不能继承父类构造函数内的属性和方法
缺点:
· 只能继承父类原型的属性和方法,不能继承父类构造函数内的属性和方法;
· 父类和子类的构造函数都指向了同一个对象。
4、 Object.create(父类原型)
Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的proto。
*基于方法3的优化,解决了父类和子类的构造函数指向同一个对象的问题。
function Food(i){ this.name = i } Food.prototype.use = "eat"; function Fish(x,y){ this.color = x; this.weight = y } Fish.prototype = Object.create(Food.prototype); Fish.prototype.constructor = Fish; console.log(Food.prototype.constructor === Food,Fish.prototype.constructor === Fish); //true true var fish = new Fish("golden","1kg","Salmon"); console.log(fish.name,fish.use); //undefined "eat"
缺点:
只能继承父类原型的属性和方法,不能继承父类构造函数内的属性和方法。
5、call/apply + Object.create(父类原型)
function Food(i){ this.name = i } Food.prototype.use = "eat"; function Fish(x,y,z){ Food.call(this,z); this.color = x; this.weight = y } Fish.prototype = Object.create(Food.prototype); Fish.prototype.constructor = Fish; var fish = new Fish("golden","1kg","Salmon"); console.log(fish.name,fish.use);
这样,前面的问题,都有效得到解决,算是比较完美的一个方案。
6、ES6 class
ES6中加入了静态方法和属性,也能通过 extends 继承。
class Food{ static staticFn(){ return "static-fn" }; static staticVal = "static-val"; constructor(i){ this.name = i }; info(){ return "demo-"+this.name } } class Fish extends Food{ constructor(x,y,z){ super(z); this.color = x; this.weight = y } } const fish = new Fish("golden","1kg","Salmon"); console.log(fish.name,fish.info()); console.log(Fish.staticFn(),Fish.staticVal);
网友评论文明上网理性发言 已有0人参与
发表评论: