怎么深刻理解 new 操做符

和其余高级语言同样 JavaScript 也有 new 操做符,咱们知道 new 能够用来实例化一个类,从而在内存中分配一个实例对象。 但在 JavaScript 中,万物皆对象,为何还要经过 new 来产生对象? 带着这个问题,咱们一步步来分析和理解 new 的一些特性:app

一、认识 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
 
代码解读以下:
this

  L1-3: 建立了一个函数Animal,并在其 this 上定义了属性:name,name的值是函数被执行时的形参。
  L4 : 在 Animal 对象(Animal自己是一个函数对象)上定义了一个静态属性:color,并赋值“black”
  L5-7:在 Animal 函数的原型对象 prototype 上定义了一个 say() 方法,say方法输出了 this 的 name 值。
  L8: 经过 new 关键字建立了一个新对象 cat
  L10-14: cat 对象尝试访问 name 和 color 属性,并调用 say 方法。
  L16-20: Animal 对象尝试访问 name 和 color 属性,并调用 say 方法。
  
  
  
二、剖析 new 的内部原理
prototype

 第8行代码是关键: 
var cat = new Animal("cat");
Animal 自己是一个普通函数,但当经过new来建立对象时,Animal 就是构造函数。
对象

JS引擎执行这句代码时,在内部作了不少工做,用伪代码模拟其内部流程以下:继承

new Animal("cat") = {
 
    var obj = {};
 
    obj.__proto__ = Animal.prototype;
 
    var result = Animal.call(obj,"cat");
 
    return typeof result === 'object'? result : obj;
}
ip

将上述流程分为 4 个步骤来理解:内存

【1】建立一个空对象 obj;原型链

【2】把 obj 的__proto__ 指向构造函数 Animal 的原型对象 prototype,此时便创建了 obj 对象的原型链:obj->Animal.prototype->Object.prototype->nullget

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

         当这句执行完以后,obj 便产生了属性 name 并赋值为 "cat"。关于 call 的用法请参考:深刻理解 call、apply 和 bind

【4】考察第 3 步的返回值,若是无返回值 或者 返回一个非对象值,则将 obj 做为新对象返回;不然会将 result 做为新对象返回。

 

根据以上过程,咱们发现 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.say() ->   Animal.say is not a function
须要注意的是,Animal 先查找自身的 name,找到了 name,但这个 name 并非咱们定义的 name,而是函数对象内置的属性,通常状况下,函数对象在产生时会内置 name 属性并将函数名做为赋值(仅函数对象)。

另外,Animal 在自身没有找到 say() 方法,也会沿着其原型链查找,Animal 的原型链以下所示:
 Animal.__proto__
 function(){}
 Animal.__proto__ == Function.prototype
 true
 Function.prototype.__proto__ == Object.prototype
 true
 Object.prototype.__proto__
 null


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

 因为 Animal 的原型链上也没有定义 say 方法,所以返回异常提示。

三、探索 new 的真正意义
对 new 运算符有了较深刻的理解以后,咱们再回到开篇提到的问题:在JavaScript 中,万物皆对象,为何还要经过 new 来产生对象?

要弄明白这个问题,咱们首先要搞清楚 cat 和 Animal 的关系:

【1】cat 继承了 Animal 对象
经过上面的分析咱们发现, cat 经过原型链继承了 Animal 中的部分属性,所以咱们能够简单的认为:Animal 和 cat 是继承关系。

【2】cat 是 Animal 的实例
cat 是经过 new 产生的对象,那么 cat 究竟是不是 Animal 的实例对象? 咱们先来了解一下JS是如何来定义实例对象:

A instanceof B

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

cat instanceof Animal; //true

从结果看,cat 确实是 Animal 实例,要想更加证明这个结果,咱们再来了解一下 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 的判断结果。

所以,经过 new 建立的 对象 和 构造函数 之间创建了一条原型链,原型链的创建,让本来孤立的对象有了依赖关系和继承能力,让JavaScript 对象能以更合适的方式来映射真实世界里的对象,这是面向对象的本质。

四、实战演练 
 下面是一个经典例子,涉及 new 、this、以及 原型链 相关问题,请看代码:


function Foo(){
    getName = function(){
        console.log(1)
    }
    return this;
}
Foo.getName = function(){
    console.log(2)
}
Foo.prototype.getName = function(){
    console.log(3)
}
var getName = function(){
    console.log(4)
}
function getName(){
    console.log(5)
}
//output : ?
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

 

相关连接:https://ke.qq.com/course/256212?flowToken=1001258

143046757

相关文章
相关标签/搜索