2014-04-08 44 views
8

我读过关于JavaScript中的“新”关键字的主题(What is the 'new' keyword in JavaScript?)。但是,我仍然在雾中。让我们来谈谈这个例子:关键字“新”在javascript中的含义

var foo = function() { 
    return { 
     setA: function(a) { 
      this.a = a; 
     }, 
     readA: function() { 
      console.log(this.a); 
     } 
    }; 
}; 

现在有什么关于这些两段代码:

一:

var bob1 = foo(); 
bob1.setA(10); 
bob1.readA(); 

二:

var bob2 = new foo(); 
bob2.setA(10); 
bob2.readA(); 

我看不出有什么差别在我的水平。那么使用关键字“新”的收益是多少?

+3

相关:[构造函数VS厂功能(http://stackoverflow.com/questions/8698726/constructor-function-vs-factory-functions) –

+0

我认为它与此相关http://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript –

+1

@ 3506238:OP已阅读。 –

回答

4

如果你的函数直接返回对象,那么你不需要运算符newnew键不止于此。

比方说

function Animal(kind, name) { 
    this.kind = kind; 
    this.name = name; 
} 

Animal.prototype.walk = function() { 
    console.log('Walking'); 
} 

然后你正在做

var animal = new Animal(); 

Javascript引擎将做以下的事情

var o = Object.create(Animal.prototype) 
    Animal.apply(o, arguments); 
    return o; 

Object.create会做Animal功能的prototype对象的原型继承。所以animal对象将有它自己的属性和它的继承属性。

1

如果构造函数foo返回一个对象,则new foo()与直接调用函数foo()相同。我们可以证明是这样的话通过检查ECMAScript behavior for new

返回调用的结果[建设]上构造 [即,构造函数]内部方法...

函数的[[Construct]] internal method是调用函数的[[Call]]内部方法(这只是函数的正常行为)的特殊包装。让我们来看看的[[Construct]]看看到底这个包装的行为:

8)让结果是调用˚F [由new调用函数]的[[呼叫]]内部属性的结果,提供obj作为this值并提供作为参数传递给[[Construct]]的参数列表。 9)如果Type(结果)为Object,则返回结果

10)退货obj

在你的情况下,你的构造函数foo返回一个对象,所以[[Construct]]步骤9(因此,反过来,new foo())返回该对象。但是我们在步骤10中看到[[Construct]]可能返回一些其他值,称为obj,这等于构造函数中的this值。让我们倒带,看看这是所有关于:

1)让OBJ是一个新创建的原生ECMAScript的对象。

...

4)让是参数调用 “prototype” F的[[获取]]内部属性的值。

5)如果Type()是对象,则[[原型]]内部的OBJ属性设置为

这里,我们看到的new真正的力量:如果构造函数没有返回一个对象(因此[[Construct]]操作由new推出被允许返回obj),然后原型继承发生。 obj(又名obj.__proto__)的[[Prototype]]被设置为构造函数方法的prototype属性。这意味着如果foo未返回对象(而是修改this),并且设置了foo.prototype.someProp,则从var instance = new foo()返回的实例将有权访问instance.someProp

因此,编写代码以不同的方式可能是:

var foo = function() { }; 
foo.prototype.setA = function(a) { this.a = a; }; 
foo.prototype.setA = function(a) { console.log(this.a); }; 

在这种情况下,产生new foo()一个对象的原型链包括foo.prototype,而foo()没有。这有利于降低内存使用量:这里的所有foo实例共享通用原型方法,而不是让每个实例都具有自己独立的功能。

3

我还在雾里约new;让我们来谈谈这个例子:

var foo = function() { 
    return { 
     setA: function(a) { 
      this.a = a; 
     }, 
     readA: function() { 
      console.log(this.a); 
     } 
    }; 
}; 

我们不应该谈论这个例子。不管我们是否使用new这个功能不会有所作为,因为the way new works:创建

  1. 一个新的对象,从foo.prototype继承。
  2. 使用指定的参数调用构造函数foo,新创建的对象调用this bound to
  3. 构造函数返回的对象成为整个新表达式的结果 。如果构造函数不显式返回对象,则使用步骤1中创建的对象代替 。 (通常构造函数不返回值,但可以 选择这样做,如果他们想覆盖正常的对象创建 过程。)

第3步是看这里的东西。您正在创建并返回一个对象(对象文字),因此将被分配到bob1。通常,构造函数不需要任何东西,并且在步骤1中隐式创建的新实例(并且在函数内部可用,如this)会变成结果。

new foo()foo()都只会将您的对象文字赋值给bob变量 - 结果没有差异。您的代码完全忽略了由new创建的实例。这将在下面的例子是不同的:

function foo() { 
    this.setA = function(a) { 
     this.a = a; 
    }; 
    this.readA = function() { 
     console.log(this.a); 
    }; 
    // return this; is implicit 
} 
var bob = new foo; // OK 
var bob = foo(); // horrible error