Javascript继承,再谈

罗曼特 2018-03-12 01:47171 阅读

     说到Javascript的继承,相信只要是前端开发者都有所了解或应用,因为这是太基础的知识了。但不知各位有没有深入去理解其中的玄机与奥秘。今本人不才,但也想用自己的理解来说一说这其中的玄机和奥秘。

一、类继承的发展吏

  • function实现的继承

function的继承是完全模仿了OOP的编程思想。实现的是类的继承

  • object.create实现的继承

用object.create来修改其原型

  • es6的继承

增加了class来模拟OOP的继承实现。上述两种继承实现,他都还是支持的。

二、各时期类继承的实现

  • function继承方式的实现(OOP)
function Animate(name){
    this.name = name;
}
Animate.prototype.getName = function(){
    return this.name;
}

function Dog(name){
    Animate.apply(this,arguments);
    this.leg = 4;
}
Dog.prototype = Inherit(Animate, Dog);
Dog.prototype.say = function(){
    return 'wang';
}

//function模式的继承
function Inherit(parent, child){
    //创建一个无原型方法的类
    function f(){}
    f.prototype = parent.prototype; //将父对象的原型赋给临时对象
    f.prototype.constructor = child; //将子类构造函数绑定到 临时对象的 prototype原型上,保持子类构造函数与prototype上的一致。
    return new f(); //执行了f的构造函数,而没有执行prototype.constructor指向的构造函数
} 

var dog = new Dog('dog');
console.log('getName:' + dog.getName()); //dog
console.log("say:" + dog.say()); //wang
console.log( 'dog instanceof Animate:' + (dog instanceof Animate)); //true
console.log( 'dog instanceof Animate: ' + (dog instanceof Dog)); //true

OOP方式的继承实现网上有很多种,如:原型链,实现、组合、寄生组合继承等。上述实现为寄生组合继承在,算比较通用且完美的一种方案了。

  • object.create实现继承
    这是一个升级版本的类式继承,需要了解object.create方法。Object.create(proto, [propertiesObject]),其中proto是新创建对象的原型对象,而propertiesObject是可选的,要添加到新创建对象的可枚举属性(即其自身定义的属性,而不是原型链接上的属性)。
    我们还需要了解的方法:Object.setPrototypeOf(内部原型的写方法);Object.getPrototypeOf(内部原型的读方法)。内部原型:[[prototype]] == proto
    上述继承代码的改造后
function Animate(name){
    this.name = name;
}
Animate.prototype.getName = function(){
    return this.name;
}

function Dog(name){
    Animate.apply(this,arguments);
    this.leg = 4;
}
Inherit(Animate, Dog); //调用点改造
Dog.prototype.say = function(){
    return 'wang';
}
//继承实现方法改造
function Inherit(parent, child){
    child.prototype = Object.create(parent.prototype); //create实现parent上的原型复制
    child.prototype.constructor = child; //将构造函数指回子类
} 

var dog = new Dog('dog');
console.log('getName:' + dog.getName()); //dog
console.log("say:" + dog.say()); //wang
console.log( 'dog instanceof Animate:' + (dog instanceof Animate)); //true
console.log( 'dog instanceof Animate: ' + (dog instanceof Dog)); //true

2.1 对prototype的尝试

上述示例中用了Object.create方法创建一个对象,然后再赋值给Prototype,而为什么不用Object.setPrototypeOf方法直接改变其Prototype的值呢。原因摘录来源于MDN:

由于现代 JavaScript 引擎优化属性访问所带来的特性的关系,更改对象的 [[Prototype]]在各个浏览器和 JavaScript 引擎上都是一个很慢的操作。其在更改继承的性能上的影响是微妙而又广泛的,这不仅仅限于 obj.proto = ... 语句上的时间花费,而且可能会延伸到任何代码,那些可以访问任何[[Prototype]]已被更改的对象的代码。如果你关心性能,你应该避免设置一个对象的 [[Prototype]]。相反,你应该使用 Object.create()来创建带有你想要的[[Prototype]]的新对象。

对象继承的实现:

var animate = {
    name: "name"
};
Object.setPrototypeOf(animate,{
    getName: function(){
        return this.name;
    }
});

var dog = {
    leg: 4
};
Object.setPrototypeOf(dog,{
    say: function(){
        return 'wang';
    }
}); 
Object.setPrototypeOf(Object.getPrototypeOf(dog),Object.getPrototypeOf(animate));

console.log('getName:' + dog.getName()); //dog
console.log("say:" + dog.say()); //wang

三、ES6类继承的实现

es6对类继承提供了原生的支持,这让Javascript更像后端语言了,简单使用如下:

class Animate{
    constructor(name){
        this.name = name
    }
    getName(){
        return this.name;
    }
}

class Dog extends Animate{
    constructor(name){
        super(name);
        this.leg = 4;
    }
    say(){
        return "wang";
    }
}
var dog = new Dog('dog');
console.log('getName:' + dog.getName()); //dog
console.log("say:" + dog.say()); //wang
console.log( 'dog instanceof Animate:' + (dog instanceof Animate)); //true
console.log( 'dog instanceof Animate: ' + (dog instanceof Dog)); //true

四、总结及疑问

     经过本文梳理,你是否发现Javascript的类继承实现越来越简单,更接近于Java,.net这类静态编译语言了,或许这就是所谓的万物归一的哲学道理。但在此还是存在一个极大的疑问:Object.setPrototypeOf方法在MDN不建议使用,说是更改内部的[[prototype]]属性存在性能问题 和 影响。不知道其影响为何,望大神们指定

回复数量: 0
暂无评论~~
  请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!