• js中的new操作符与Object.create()的作用与区别


    js中的new操作符与Object.create()的作用与区别

    https://blog.csdn.net/mht1829/article/details/76785231

     一、new 操作符

    JavaScript 中 new 的机制实际上和面向类的语言完全不同。

    在 JavaScript 中,构造函数只是一些使用 new 操作符时被调用的函数。它们并不会属于某个类,也不会实例化一个类。实际上,它们甚至都不能说是一种特殊的函数类型,它们只是被 new 操作符调用的普通函数而已。

    使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
    1. 创建(或者说构造)一个全新的对象。
    2. 这个新对象会被执行 [[ 原型 ]]  ([[Prototype]])连接。
    3. 这个新对象会绑定到函数调用的 this 。
    4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。

    二、Object.create

    调用Object.create(..) 会凭空创建一个“新”对象并把新对象内部的 [[Prototype]] 关联到你指定的对象。

    分别使用这两个方法进行原型继承,

    进行一个小试验:

    function A(id,name){
        this.id=5;
        this.name=name;
        this.sex='nan';

        this.colors=['red','blue'];
       }
       A.prototype.speak=function(){
        console.log(this.id);
       }
       function B(id,name){

        A.call(this,id,name);
        this.id=id;
        this.name=name;
       }
       //B.prototype=Object.create(A.prototype);
       B.prototype=new A();//使用new会调用一次A的构造函数,在结合使用构造函数技术时就会调用2次构造,这是第一次
       var test1=new B(3,'test1');
       var test2=new B(4,'test2');
       test1.colors.push('black');
       console.log(test1.colors); //["red", "blue", "black"]
       console.log(test2.colors); //["red", "blue", "black"]
       console.log(test1.sex);//使用Object.create() 结果为undefined;使用new时结果为‘nan’。
       //test1.speak();

    如上代码所示:当对象B的prototype通过new A()方式进行原型关联时,会产生一些副作用。第一:这里给A的this添加数据属性B也能通过[[Prototype]]链查找访问到此属性,因此此方法修改函数A会直接影响其后代(这里为函数B),后果不堪设想。

    第二:使用原型链实现继承时,原型的所有属性和方法被实例共享,这种共享对函数非常合适,对于基本类型值的属性实例可以覆盖原型,但是对于包含引用类型值的属性来说,每个实例的修改都会改变原型的属性,因为引用类型的属性包含的是一个指向引用对象的指针(如数组类型)。因此,这里通过原型继承后,原型实际上会变成另一个类型的实例。于是,原先的实例属性也就顺理成章得变成了现在的原型属性。(如B的实例对象中的colors属性)。这个副作用使用Object.create()方法也存在。

    可以使用借用构造函数技术解决这个问题。在B类型的构造函数第一行写上A.call(this,id,name);原理是:让B的实例对拥有引用类型值的属性,修改B实例时就不会修改它原型上的属性。

    第三:在创建子类型的实例时,无法向超类型的构造函数中传递参数。(实际上,是没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数)。
    原因分析: 参看new 操作过程的第3步,new会将这个新对象会绑定到函数调用的 this (相当于java语言的实例化对象,对象拥有了类A的实例属性)。所以当执行B.prototype=new A(); B.prototype就拥有了id,name和sex属性。而对象test1并没有,访问test1.sex时会通过原型链找到sex属性。

    new操作和create()操作前后B.prototype的变化具体如下图所示。图左为B默认的prototype对象,图中为new操作后B

    的prototype对象,图右为create()操作后B点prototype对象。从中可以看出共同点:
    1、B都没有B.prototype.constructor属性,(其实.constructor属性只是在B函数声明时默认的一个公有并且不可枚举

    属性,如果创建了一个新对象并替换了函数默认的 .prototype 对象引用,那么新对象并不会自动获得 .constructor 属

    性。)
    2、B的原型链上都继承了A的原型,关联了A的原型方法。

    再来看看test1对象,图左为new操作后的test1对象原型链,图右为Object.create()操作后的原型链。可以清楚的知道为什么前者test1.sex能打印出'nan',而后者为undefined。

    另外,关联原型还有1种常见的错误做法
    B.prototype = A.prototype;//和你想要的机制不一样,此时并不会创建一个关联到A.prototype的新对象,它只是让

    B.prototype直接引用了A.prototype对象。因此当你直接执行类似"B.prototype.sex=...."的赋值语句时会直接修改

    A.prototype对象本身。

    因此,要创建一个合适的关联对象,最好的方法是Object.create(..),而不是有副作用的new A()。这样做唯一的缺点

    就是需要创建一个新对象然后把旧对象抛弃掉(有性能损失:抛弃的对象需要进行垃圾回收),不能直接修改已有的

    默认对象。

    这只是ES6之前最好的办法,ES6 添加了辅助函数Object.setPrototypeOf(..),可以用标准并且可靠的方法来修改关联。

    如下图所示,此方法不必抛弃默认的 B.prototype,对其进行直接修改。

    ES6 class 继承方式

    [javascript] view plain copy
     
    1. class C {  
    2.             constructor(name, id) {  
    3.                 this.name = name;  
    4.                 this.id = id;  
    5.             }  
    6.             say() {  
    7.                 console.log(this.name)  
    8.             }  
    9.         }  
    10.   
    11.         class D extends C {  
    12.             constructor(name, id, age) {  
    13.                 super(name, id); // 这里必须先调用super方法  
    14.                 this.age = age;  
    15.             }  
    16.         }  
    17.   
    18.         let obD = new D('mht', 22, 33)  
    19.         obD.say()  
    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mht1829/article/details/76785231
    个人分类: javascript
  • 相关阅读:
    SpringMvc@RequestParam 来映射请求参数
    SpringMvc中@PathVariable注解简单的用法
    SpringMvc的学习之路
    平常的操作函数以及回调
    关于弹窗 取消 确定清空按钮的事件
    判断主表里子表不能添加相同的字段
    选择company回显appname
    树形菜单数据源
    .NET为什么要使用异步(async)编程?⭐⭐⭐⭐⭐
    通过HttpClient的方式去Curd数据⭐⭐⭐⭐
  • 原文地址:https://www.cnblogs.com/chaoyuehedy/p/9084843.html
Copyright © 2020-2023  润新知