详解javascript new的运行机制

和其他高级语言一样javascript 中也有new 运算符,我们知道new 运算符是用来实例化一个类,从而在内存中分配一个实例对象。 但在 javascript 中,万物皆对象,为什么还要通过new 来产生对象? 本文将带你一起来探索 javascript 中 new 的奥秘...

一、认识new运算符

function Animal(name){
    this.name = name;
  }
  Animal.color = "black";
  Animal.prototype.say = function(){
    console.log("I'm " + this.name);
  };
  var cat = new Animal("cat");

  console.log(
    cat.name, //cat
    cat.height //undefined
  );
  cat.say(); //I'm cat

  console.log(
    Animal.name, //Animal
    Animal.color //back
  );
  Animal.say(); //Animal.say is not a function

如果你能理解上面输出的结果,说明你已非常了解js中new和this的运行机制,请忽略本文!

我们将通过解析这个例子来加深你对js中new运算符的理解! 【如果你对js的this还不了解,请先阅读:JS作用域和this关键字】

1、代码解读

1-3行创建了一个函数Animal,并在其this上定义了属性:name,name的值是函数被执行时的形参。

第4行在Animal对象(Animal本身是一个函数对象)上定义了一个静态属性:color,并赋值“black”

5-7行在Animal函数的原型对象prototype上定义了一个say()方法,say方法输出了this的name值。

第8行通过new关键字创建了一个新对象cat

10-14行cat对象尝试访问name和color属性,并调用say方法。

16-20行Animal对象尝试访问name和color属性,并调用say方法。

2、重点解析

第8行代码是关键:

var cat = new Animal("cat");
JS引擎执行这句代码时,在内部做了很多工作,用伪代码模拟其工作流程如下:

new Animal("cat") = {

  var obj = {};

  obj.__proto__ = Animal.prototype;

  var result = Animal.call(obj,"cat");

  return typeof result === 'obj'? result : obj;
}

(1)创建一个空对象obj;

(2)把obj的__proto__ 指向Animal的原型对象prototype,此时便建立了obj对象的原型链:obj->Animal.prototype->Object.prototype->null

【如果你不了解JS原型链,请先阅读:JS原型和原型链】

(3)在obj对象的执行环境调用Animal函数并传递参数“cat”。 相当于var result = obj.Animal("cat")。

当这句执行完之后,obj便产生了属性name并赋值为"cat"。【关于JS中call的用法请阅读:JS的call和apply】

(4)考察第3步返回的返回值,如果无返回值或者返回一个非对象值,则将obj返回作为新对象;否则会将返回值作为新对象返回。

理解new的运行机制以后,我们知道cat其实就是过程(4)的返回值,因此我们对cat对象的认知就多了一些

cat的原型链是:cat->Animal.prototype->Object.prototype->null

cat上新增了一个属性:name

分析完了cat的产生过程,我们再看看输出结果:

cat.name -> 在过程(3)中,obj对象就产生了name属性。因此cat.name就是这里的obj.name

cat.color -> cat会先查找自身的color,没有找到便会沿着原型链查找,在上述例子中,我们仅在Animal对象上定义了color,并没有在其原型链上定义,因此找不到。

cat.say -> cat会先查找自身的say方法,没有找到便会沿着原型链查找,在上述例子中,我们在Animal的prototype上定义了say,因此在原型链上找到了say方法。

另外,在say方法中还访问this.name,这里的this指的是其调用者obj,因此输出的是obj.name的值。

对于Animal来说,它本身也是一个对象,因此,它在访问属性和方法时也遵守上述查找规则,所以:

Animal.color -> "black"

Animal.name -> "Animal" , Animal先查找自身的name,找到了name,注意:但这个name不是我们定义的name,而是函数对象内置的属性。

一般情况下,函数对象在产生时会内置name属性并将函数名作为赋值(仅函数对象)。

Animal.say -> Animal在自身没有找到say方法,也会沿着其原型链查找,话说Animal的原型链是什么呢?

从测试结果看:Animal的原型链是这样的:

Animal->Function.prototype->Object.prototype->null

因此Animal的原型链上没有定义say方法!

二、new存在的意义

认识了new运算符之后,我们再回到开篇提到的问题:JS中万物皆对象,为什么还要通过new来产生对象?要弄明白这个问题,我们首先要搞清楚cat和Animal的关系。

通过上面的分析,我们发现cat继承了Animal中的部分属性,因此我们可以简单的理解:Animal和cat是继承关系。

另一方面,cat是通过new产生的对象,那么cat到底是不是Animal的实例对象? 我们先来了解一下JS是如何来定义“实例对象”的?

A instanceof B

如果上述表达式为true,JS认为A是B的实例对象,我们用这个方法来判断一下cat和Animal

cat instanceof Animal; //true

从执行结果看:cat确实是Animal实例,要想证实这个结果,我们再来了解一下JS中instanceof的判断规则:

var L = A.__proto__;
var R = B.prototype;
 if(L === R)
return true;

如果A的__proto__ 等价于 B的prototype,就返回true

在new的执行过程(2)中,cat的__proto__指向了Animal的prototype,所以cat和Animal符合instanceof的判断结果。因此,我们认为:cat是Animal的实例对象。

在javascript中, 通过new可以产生原对象的一个实例对象,而这个实例对象继承了原对象的属性和方法。因此,new存在的意义在于它实现了javascript中的继承,而不仅仅是实例化了一个对象!

(0)

相关推荐

  • js中关于new Object时传参的一些细节分析

    1, 参数是一个对象,核心js对象(native ECMAScript object)或宿主对象(host object),那么将直接返回该对象. 其生成的对象构造器仍然是所传参数对象的构造器.这样造成的后果是虽然该对象是new Object,但其constructor不一定是Object. 复制代码 代码如下: function Person(){this.name='jack';} var w = new Object(window), d = new Object(document), p

  • Javascript new关键字的玄机 以及其它

    (接上)先看张对老手不新鲜但对菜鸟很有趣的图: What the heck is that? 简直是luan lun. new 抛开上面的图,先看看上篇文章留下的第二个问题,让我们在构造器的函数体内加点东西,看会发生什么. function A(){this.p = 1}var a = new A() 会得到如下结果: 为什么用new关键字构造出来的a,会获得p这个属性?new A()这行代码做了什么事情?根据上篇文章中Function的创建过程第4步,A这个对象会有一个Construct属性(

  • js之ActiveX控件使用说明 new ActiveXObject()

    什么是 ActiveX 控件? ActiveX 控件广泛用于 Internet.它们可以通过提供视频.动画内容等来增加浏览的乐趣.不过,这些程序可能出问题或者向您提供不需要的内容.在某些情况下,这些程序可被用来以您不允许的方式从计算机收集信息.破坏您的计算机上的数据.在未经您同意的情况下在您的计算机上安装软件或者允许他人远程控制您的计算机.考虑到这些风险,您应该在完全信任发行商的情况下才安装这些程序. 当 Windows 阻止 ActiveX 控件的安装时,您应该做什么? 您可能不应该安装该 A

  • javascript new一个对象的实质

    以前这些东西自己清楚,可是却解释不出来,也没有去深究这些东西.今天在看<悟透JavaScript>的时候,看到作者的描述,"茅厕"顿开. 现摘录如下,作者说的很是清楚: 用 var anObject = new aFunction() 形式创建对象的过程实际上可以分为三步: 第一步是建立一个新对象: 第二步将该对象内置的原型对象设置为构造函数prototype引用的那个原型对象: 第三步就是将该对象作为this参数调用构造函数,完成成员设置等初始化工作.

  • 在.NET中使用Newtonsoft.Json转换,读取,写入的方法介绍

    全局引用 using Newtonsoft.Json; using Newtonsoft.Json.Converters; //把Json字符串反序列化为对象 目标对象 = JavaScriptConvert.DeserializeObject(JSON字符串, typeof(目标对象)); //把目标对象序列化为Json字符串 stringJson字符串 = JavaScriptConvert.SerializeObject(目标对象); 1.引用Newtonsoft.Json.dll: 2.

  • 关于js new Date() 出现NaN 的分析

    此NaN不为NaN: 程序代码如下: 复制代码 代码如下: var date =new Date(d); if(!date || !date.getFullYear) { return; } return S.Date.format(d,'yyyy-mm-dd');//格式化函数,跟此文无关 在其他浏览器下正常,但是在ie下,程序报错 在ie调试器下,发现date 为NaN,如图: 如果是NaN,那么if判断会返回true,会 return "",但是诡异的一幕发生了, 代码说明if判

  • 正则(JS)re=new RegExp("^\\d*$");与re=/^\d*$/;之间区别?

    以下代码结果为:FALSE,TRUE,TRUE      请问结果中为什么第一个为FALSE?      <form   name=form1>      字符串:<input   name="t1"   value="123456">      模式:/<input   name="t2"   value="^\d*$">/      </form>      <scri

  • javascript中IE浏览器不支持NEW DATE()带参数的解决方法

    复制代码 代码如下: var date1=new Date(dateTimes[z][1]); 在火狐下 可以正常取得时间,在IE7下 却是 NaN.纠结老长时间,放弃了new date 然后再老外的论坛中找了一段段代码可以兼容所有浏览器的格式化日期代码: 复制代码 代码如下: function NewDate(str) { str = str.split('-'); var date = new Date(); date.setUTCFullYear(str[0], str[1] - 1, s

  • JavaScript中的new的使用方法与注意事项

    原文: JavaScript, We Hardly new Ya  --Douglas Crockford.    http://yuiblog.com/blog/2006/11/13/javascript-we-hardly-new-ya/ 引用 JavaScript是一门基于原型的语言,但它却拥有一个 new 操作符使得其看起来象一门经典的面对对象语言.那样也迷惑了程序员们,导致一些有问题的编程模式. 其实你永远不需要在JavaScript使用 new Object().用字面量的形式{}去

  • 详解javascript new的运行机制

    和其他高级语言一样javascript 中也有new 运算符,我们知道new 运算符是用来实例化一个类,从而在内存中分配一个实例对象. 但在 javascript 中,万物皆对象,为什么还要通过new 来产生对象? 本文将带你一起来探索 javascript 中 new 的奥秘... 一.认识new运算符 function Animal(name){ this.name = name; } Animal.color = "black"; Animal.prototype.say = f

  • 详解JavaScript的垃圾回收机制

    目录 为什么需要垃圾回收(GC) 什么是垃圾回收 垃圾产生 垃圾回收策略 引用计数标记 循环引用引发的问题 解决方法 引用计数算法的优缺点 标记清除算法 核心思想 标记清除算法优缺点 标记整理算法 V8引擎的垃圾回收 回收新生代对象 对象晋升机制 回收老生代对象 参考文档: 总结 为什么需要垃圾回收(GC) 程序和人一样,生活时间长了会产生垃圾,程序在运行过程中也会产生垃圾,垃圾积攒过多后,会导致程序运行速度变慢. 在JavaScript中的字符串.对象.数组等数据的内存是不固定的,只有真正使用

  • 详解Javascript中new()到底做了些什么?

    前言 和其他高级语言一样 javascript 中也有 new 运算符,我们知道 new 运算符是用来实例化一个类,从而在内存中分配一个实例对象. 但在 javascript 中,万物皆对象,为什么还要通过 new 来产生对象? 本文将带你一起来探索 javascript 中 new 的奥秘... 要创建 Person 的新实例,必须使用 new 操作符. 以这种方式调用构造函数实际上会经历以下 4个步骤: (1) 创建一个新对象: (2) 将构造函数的作用域赋给新对象(因此 this 就指向了

  • 详解JavaScript 的执行机制

    一.关于javascript javascript是一门单线程语言,在最新的HTML5中提出了Web Worker,但javascript是单线程这一核心仍未改变. 为什么js是单线程的语言?因为最初的js是用来在浏览器验证表单操纵DOM元素的.如果js是多线程的话,两个线程同时对一个DOM进行了相互冲突的操作,那么浏览器的解析是无法执行的. Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行.在主线程运行的同

  • 详解JavaScript基于面向对象之继承

    一.面相对象继承机制       这个实例使用UML很好的解释了继承机制.       说明继承机制最简单的方式是,利用一个经典的例子就是几何形状.实际上,几何形状只有两种,即椭圆形(是圆形的)和多边形(具有一定数量的边).圆是椭圆的一种,它只有一个焦点.三角形.矩形和五边形都是多边形的一种,具有不同数量的边.正方形是矩形的一种,所有的边等长.这就构成了一种完美的继承关系,很好的解释了面向对象的继承机制.        在这个例子中,形状是椭圆形和多边形的基类(通常我们也可以叫它父类,所有类都由

  • js对象实例详解(JavaScript对象深度剖析,深度理解js对象)

    这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕. 平时发的文章基本都是开发中遇到的问题和对最佳解决方案的探讨,终于忍不住要写一篇基础概念类的文章了. 本文探讨以下问题,在座的朋友各取所需,欢迎批评指正: 1.创建对象 2.__proto__与prototype 3.继承与原型链 4.对象的深度克隆 5.一些Object的方法与需要注意的点 6.ES6新增特性 下面反复提到实例对象和原型对象,通过构造函数 new

  • 详解JavaScript作用域 闭包

    JavaScript闭包,是JS开发工程师必须深入了解的知识.3月份自己曾撰写博客<JavaScript闭包>,博客中只是简单阐述了闭包的工作过程和列举了几个示例,并没有去刨根问底,将其弄明白! 现在随着对JavaScript更深入的了解,也刚读完<你不知道的JavaScript(上卷)>这本书,所以乘机整理下,从底层和原理上去刨一下. JavaScript并不具有动态作用域,它只有词法作用域.词法作用域是在写代码或者说定义时确定的,而动态作用域是在运行时确定的.了解闭包前,首先我

  • 详解JavaScript执行模型

    JavaScript执行模型 引言 JavaScript是一个单线程(Single-threaded)异步(Asynchronous)非阻塞(Non-blocking)并发(Concurrent)语言,这些语言效果通过一个调用栈(Call Stack).一个事件循环(Event Loop).一个回调队列(Callback Queue)有些时候也叫任务队列(Task Queue)与跟运行环境相关的API组成. 概念 调用栈 Call Stack 调用栈是一个LIFO后进先出数据结构的函数运行栈,它

  • 详解JavaScript什么情况下不建议使用箭头函数

    目录 this指向原理 问题的由来 内存的数据结构 函数 环境变量 箭头函数的缺点 不适用的场景 总结 箭头函数作为ES6新增的语法,在使用时不仅能使得代码更加简洁,而且在某些场景避免this指向问题.但是箭头函数不是万能的,也有自己的缺点以及不适用的场景,虽然可以解决this只想问题,但是也可能会带来this指向问题.具体场景具体分析,本文就深入探讨箭头函数. 箭头函数没有自己的this,其this取决于上下文中定义的this. this指向原理 问题的由来 学懂 JavaScript 语言,

  • 详解JavaScript基于面向对象之继承实例

    javascript面向对象继承的简单实例: 作为一门面向对象的语言,继承自然是它的一大特性,尽管javascript的面向对象的实现机制和和c#和java这样典型的面向对象不同,但是继承的基本特点还是具有的,简单的说就是获得父级的方法和属性,下面是一段简单的实例,大家有兴趣可以分析一下: window.onload = function(){ function parent(age,name){ this.age = age; this.name = name; } parent.protot

随机推荐