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

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

2017年08月06日 19:19:26

阅读数:1058

一、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 继承方式

  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. class D extends C {
  11. constructor(name, id, age) {
  12. super(name, id); // 这里必须先调用super方法
  13. this.age = age;
  14. }
  15. }
  16. let obD = new D('mht', 22, 33)
  17. obD.say()
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mht1829/article/details/76785231
个人分类: javascript

js中的new操作符与Object.create()的作用与区别的更多相关文章

  1. C#中泛型的解释(object,list,var,dynamic的区别)

    泛型是 2.0 版 C# 语言和公共语言运行库 (CLR) 中的一个新功能.泛型将类型参数的概念引入 .NET Framework,类型参数使得设计如下类和方法成为可能:这些类和方法将一个或多个类型的 ...

  2. eclipse中build path与Web Deployment Assembly的作用,区别

    转自:https://blog.csdn.net/heart_mine/article/details/79402792 以下内容只为做个笔记记录已下,有问题可以留言,欢迎补充. 今天在eclipse ...

  3. JS中的 new 操作符简单理解

    首先上一一个简单的 new 操作符实例 var Person = function(name){ this.name = name; this.say = function(){ return &qu ...

  4. JS中的一元操作符

    表达式 一元操作符 优先级 结合性 运算顺序 表达式是什么? 就是JS 中的一个短语,解释器遇到这个短语以后会把对它进行计算,得到一个结果参与运算,我们把这种要参与到运算中的各种各样的短语称为表达式. ...

  5. JS中的new操作符

    在JS中定义一个构造函数,然后用new操作符构造对象obj,JS代码如下. function Base(){ this.name = "swf"; this.age =20; } ...

  6. JS中的相等性判断===, ==, Object.is()

    首发地址:http://www.geeee.top/2019/11/15/equality-comparisons/,转载请注明出处 相信刚接触JS的人都会被他的想等性判断给整糊涂,看看下面代码,你能 ...

  7. js中,全局变量与直接添加在window属性的区别

    在js中定义的全局变量是挂在window下的,而window的属性也一样,那么这两者有什么区别呢? 其实这两者还是有小小的区别的,全局变量是不能通过delete操作符删除的,而直接定义在window上 ...

  8. js中的等值运算符(抽象相等==与严格相等===的区别)

    js中的等值运算符 js中的相等分为抽象相等和严格相等,他们有什么区别呢. 在说具体算法前,先提下JS数据类型,JS数据类型分为6类:Undefined Null String Number Bool ...

  9. js中slice(),splice(),split(),substring(),substr()的使用方法和区别

    1.slice(): Array和String对象都有 在Array中  slice(i,[j]) i为开始截取的索引值,负数代表从末尾算起的索引值,-1为倒数第一个元素j为结束的索引值,缺省时则获取 ...

随机推荐

  1. 网页渗透-wpscan

    wpscan –url www.xxx.com #扫描基本信息 wpscan –url www.xxx.com –enumerate p #扫描插件基本信息 wpscan –url www.xxx.c ...

  2. CVPR,ICCV和ECCV,计算机视觉三大顶级盛会

    简介:https://blog.csdn.net/hualitlc/article/details/11099693 近几年ICCV,CVPR,和ECCV论文列表:https://www.xuebuy ...

  3. Class Loading Deadlocks

    By tomas.nilsson on Feb 28, 2010 Mattis keeps going strong, in this installment you get to learn eve ...

  4. 【重要】拷贝NIOS II工程后,修改工程前必须要做的10件事

    1.拷贝现有工程到新的目录2.打开Quartus II工程文件3.打开NIOS II EDS软件4.切换工作空间到当前的新工程根目录5.在NIOS II EDS软件中将已有的软件工程先删除掉(不要勾选 ...

  5. Gulp资料大全:入门、插件、脚手架、包清单

    awesome-gulp中文版 一份gulp的资源,插件和使用实例清单, 致力于打造更好的前端工程构建流程. 被老外的awesome 清单刺激到,觉得有必要翻译一份,为国产的程序员们做点事情,本清单将 ...

  6. CentOS下安装PHP的AMQP扩展方法和步骤

    AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计.基于此协议的客户端 ...

  7. [LeetCode 题解]: Remove Nth Node From End of List

    Given a linked list, remove the nth node from the end of list and return its head. For example, Give ...

  8. 使用web API和NPOI导出Excel

    使用MVC controller输出excel的例子,自不待言,例子满天飞. 由于本项目使用的是Asp.net MVC API,因此在本项目使用API,实现了文件下载功能.代码的原理很简单,基本上是老 ...

  9. NLP常用开源/免费工具

    一些常见的NLP任务的开源/免费工具, *Computational Linguistics ToolboxCLT http://complingone.georgetown.edu/~linguis ...

  10. Django集成TinyMCE(admin后台+前台)

    Django版本1.11,操作系统windows 7,在pycharm的terminal中使用pip install django-tinymce下载tinymce(前提是装的python里有pip功 ...