• Javascript继承,再谈


         说到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]]属性存在性能问题 和 影响。不知道其影响为何,望大神们指定

  • 相关阅读:
    拼接表达式树的原理
    ql Server 2012完全卸载方法
    jquery tmpl 详解
    Entity Framework(EF) Code First将实体中的string属性映射成text类型的几种方式
    Entity Framework 数据生成选项DatabaseGenerated
    Entity Framework 复杂类型
    EF Code First 学习笔记:约定配置
    比特币转账流程
    mmap 的理解
    copy_to_user,copy_from_user,get_user,put_user函数比较
  • 原文地址:https://www.cnblogs.com/cqhaibin/p/8542283.html
Copyright © 2020-2023  润新知