最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 【JS】画图法快速理解原型链prototype/constructor与JS继承

    正文概述 掘金(anysunflower同学)   2021-02-09   610

    原型相关名词概念解释


    名词用途描述其他
    [[Construct]]对象的一个内置方法,用于创建对象,通过new或者super关键字调用。该内置方法的第一个参数是传入的参数列表。第二个参数是new所初始化的对象。最后返回一个Obejct。constructor调用实现该内置方法constructor对象用来创建和初始化一个对象。是个具有prototype属性的function对象。(这个prototype属性保存的是一个指针,指向了prototype对象所在的位置)。通过new创建对象的时候会调用constructor方法,不使用new调用constructor的话,根据具体实现可能会得到不同结果。比如:new Date()得到的是当前日期Date对象,Date()则是当前时间字符串constructor属性指向constructor对象保存的是引用prototype属性指向一个prototype对象所在的位置每个函数都有该属性,这个属性中保存的是引用,而不是具体的对象prototype对象对象的用途是包含可以由特定类型的所有实例共享的属性和方法。该对象的 __proto____属性指向了Object的原型proto_实例的属性,指向实例的原型对象保存的也是对象的引用

    ecma262/#constructor

    function Parent(){
      this.name = 'parent';
    }
    var a = new Parent();
    console.log(Parent.prototype);
    console.log(Parent.constructor);
    console.log(Parent.prototype.constructor);
    console.log(a.prototype);
    console.log(a.__proto__);
    console.log(a.constructor);
    

    根据上述代码,我们来分析每个函数对应的prototype和constructor

    对象取值
    Parent的prototype对象一个具有constructor属性的Object(图:prototype 1-1 )Parent.prototype属性Parent的prototype对象的引用Parent.constructorƒ Function() { [native code] }Parent.prototype.constructorƒ Parent(){this.name = 'parent';}a.prototypeundefineda.proto__与Parent.prototype相同a.constructorƒ Parent(){this.name = 'parent';}

    【JS】画图法快速理解原型链prototype/constructor与JS继承

    把这些关系抽象成关系图就是如下:(非常建议大家自己写段代码,然后自己画一遍这个关系图,就会非常清晰)

    【JS】画图法快速理解原型链prototype/constructor与JS继承

    • 抽象的原型构造函数关系图

    【JS】画图法快速理解原型链prototype/constructor与JS继承

    Function prototype reference

    new具体的过程


    1. 一个继承自 *Foo*.prototype 的新对象被创建。
    2. 使用指定的参数调用构造函数 Foo,并将 this 绑定到新创建的对象。new *Foo* 等同于 new Foo(),也就是没有指定参数列表,Foo 不带任何参数调用的情况。
    3. 由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。(一般情况下,构造函数不返回值,但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤)
    new Parent() = {
        var obj = {};
    	obj.__proto__ = Parent.prototype; // 此时便建立了obj对象的原型链:
    	// obj->Parent.prototype->Object.prototype->null
    	var result = Person.call(obj); // 相当于obj.Person("John")
    	return typeof result === 'object' ? result : obj; // 如果无返回值或者返回一个非对象值,则将obj返回作为新对象
    }
    

    手写一个new方法

    function _new(fn,...arg){
        const obj = Object.create(fn.prototype);
        const ret = fn.apply(obj,arg);
        return ret instanceof Object?ret:obj;//考虑到基本数据类型
    }
    

    mozilla.org-new

    alexzhong22c js-new-happen

    Object.getPrototypeOf

    var o = new C();

    //o是C的实例,所以

    Object.getPrototypeOf(o) === C.prototype

    Object.getPrototypeOf 返回的是实例对象的原型

    因为Object是构造函数

    Object.getPrototypeOf(Object) 得到的是// f(){[native code]}

    Object.getPrototypeOf( Object ) === Function.prototype; // true

    因为把Object看作对象,Object是个函数

    所以Object.getPrototypeOf( Object )返回的就是函数对象的原型Function.prototype

    Object.prototype是构造出来的对象的原型。

    继承的实现方式


    构造函数直接实现

    function SuperType(){
        this.property =true;
    }
    
    function SubType(){
          SuperType.call(this);
    }
    
    //修改父类上的原型内容
    SuperType.prototype.getType = function(){
        return 'add';
    }
    var instance = new SubType();
    
    console.log(instance.property);
    //true
    console.log(instance.getType());
    //报错:Uncaught TypeError: instance.getType is not a function
    
    • 问题:通过构造方法继承的子类,可以获取到父类构造函数当中的所有属性。
      • 子类就无法获取到父类prototype上变化的属性和方法。
      • 不好进行函数复用

    原型继承

    function SuperType(){
        this.property =true;
        this.colors = ['red','green'];
    }
    SuperType.prototype.getSuperValue = function(){
        return this.property;
    }
    
    var parent = new SuperType();
    function SubType(){
        this.property = false;//子类重写父类属性
    }
    //把子类的原型设置为父类的一个新的实例对象
    //父类的实例的__proto__中指向它自己的原型对象
    //所以这样子类也可以成功访问到
    SubType.prototype = new SuperType(); 
    SubType.prototype.getSubType = function(){
        return this.property;
    }
    var instance = new SubType();
    console.log(instance.getSuperValue());//false
    instance.colors.push('blue');
    console.log(parent.colors);//'red','green',
    var instance2 = new SubType();
    console.log(instance2.colors);//'red','green','blue'
    
    • 问题:
      • 不同子类实例会共享同一个引用类型数据,所以如果有一个修改了它,其他实例访问到的也是修改之后的。
      • 创建子类实例的时候不能向构造参数传递参数。

    【JS】画图法快速理解原型链prototype/constructor与JS继承

    组合继承:构造函数+原型继承

    function SuperType(){
        this.property =true;
        this.colors = ['red','green'];
    }
    SuperType.prototype.getSuperValue = function(){
        return this.property;
    }
    
    var parent = new SuperType();
    function SubType(arg){
        SuperType.call(this,arg);
        this.property = false;//子类重写父类属性
    }
    
    SubType.prototype = new SuperType(); 
    
    SubType.prototype.getSubType = function(){
        return this.property;
    }
    var instance = new SubType();
    console.log(instance.getSuperValue());//false
    instance.colors.push('blue');
    console.log(instance.colors);//'red','green','blue'
    console.log(parent.colors);//'red','green',
    var instance2 = new SubType();
    console.log(instance2.colors);//'red','green'
    
    • 组合继承,具有了两种集成方式的有点,同时因为借用了父类的构造函数,所以每个子类实例获得了父类的属性。
      • 不足之处:每次都会调用两次超类的构造函数。一次是创建子类原型的时候,另一次是在子类构造函数内部。

    【JS】画图法快速理解原型链prototype/constructor与JS继承

    寄生继承

    • 调用函数创建对象+增强该对象的属性和方法
     function createAnother(original){
      var clone = object(original);
      clone.sayHi = function(){
        console.log('hi');
      }
      return clone;
    }
    
    var person = {
      name:"sherry",
      friends:['lisa']
    }
    var p = createAnother(person);
    

    最佳实践:寄生组合继承

    function inheritPrototype(subType,superType){
      var prototype = object(superType.prototype);  
      prototype.contructor = subType;
      subType.prototype = prototype;
    }
    

    另一种实现方式:

     function extend(Child, Parent) {
        var F = function(){};
        F.prototype = Parent.prototype;
        Child.prototype = new F();
        Child.prototype.constructor = Child;
        Child.uber = Parent.prototype;
      }
    
    • 只调用一次superType的构造函数
    • 原型链也没有改变

    参考:《Javascript高级教程》


    起源地下载网 » 【JS】画图法快速理解原型链prototype/constructor与JS继承

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元