无论如何,JavaScript中的`new`是什么意思?

flu*_*ffy 40 javascript oop

关于构造函数在Javascrpt中的工作原理,我感到非常困惑.尽管使用该语言已有好几年了(大多数情况下它就像是LISP的半命令版本),但我想更多地了解对象应该如何工作.

鉴于此代码:

function Foo(x) {
    return {
        bar: function() { return x; }
    };
}
Run Code Online (Sandbox Code Playgroud)

打电话myFoo = Foo(5)和有myFoo = new Foo(5)什么区别?或者,换句话说,Javascript中的构造函数究竟是什么的?

Mik*_*uel 49

打电话myFoo = Foo(5)和有myFoo = new Foo(5)什么区别?

该代码没有区别,因为它返回一个对象,规范说:

  • result是调用F 的[[Call]]内部属性的结果,提供obj作为this值,并将传递给[[Construct]]的参数列表作为args.
  • 如果Type(result)Object则返回结果.

由于该函数返回的结果是Object,因此使用其结果.如果它没有返回一个对象,或者如果它被检查this,你会注意到一个区别,例如,如果你把它重写为:

function Foo(x) {
  if (!(this instanceof Foo)) { return new Foo(x); }
  this.bar = function() { return x; };
}
// Now instanceof works.
alert((new Foo) instanceof Foo);
Run Code Online (Sandbox Code Playgroud)

是什么new在JavaScript做啊?

new操作将导致函数来调用this绑定到新创建的Object,其原型是函数的prototype性质.

对于用户定义的功能,

new f(a, b, c)
Run Code Online (Sandbox Code Playgroud)

相当于

// Create a new instance using f's prototype.
var newInstance = Object.create(f.prototype), result;

// Call the function
result = f.call(newInstance, a, b, c),

// If the result is a non-null object, use it, otherwise use the new instance.
result && typeof result === 'object' ? result : newInstance
Run Code Online (Sandbox Code Playgroud)

注意,语言规范实际上定义了具有两个操作的函数,[[Call]][[Construct]],因此存在一些new奇怪的行为.

例如,绑定和内置函数:

var g = f.call.bind(f);
Run Code Online (Sandbox Code Playgroud)

应该定义一个函数,在调用时,只调用f,所以g应该f在所有方面都相同,但是

new g()
Run Code Online (Sandbox Code Playgroud)

产生

TypeError: function call() { [native code] } is not a constructor
Run Code Online (Sandbox Code Playgroud)

因为内置函数Function.prototype.call支持[[Call]]而不支持[[Construct]].

Function.prototype.bind周围new和常规电话也表现不同.this调用时,该值始终是绑定的thisValue,但在使用时是一个新构造的实例new.

  • @benekastah,有两个问题.一个在标题中,一个在文本中.我首先回答了标题,现在已经编辑回答了文中的标题. (3认同)
  • 这是提供信息的,但并不完全回答这个问题. (2认同)
  • 谢谢,这最终是Javascript对象如何工作的直接解释,我在其他任何地方都找不到(包括来自我们的主要Javascript人员,他们只是说它"显而易见"和"基于原型",好像这回答了一切).+1并接受. (2认同)

CMS*_*CMS 13

在这个特定的例子中,最终结果没有区别.

这是因为您的Foo函数正在返回一个对象实例.

new运算符返回一个新创建的对象,从构造函数的原型继承,只有当函数返回原始值(或它不返回任何东西,这是技术上的undefined值).

例如:

function Foo () {
  return 5; // or "", or null, or no return statement at all (undefined)
}

var foo = new Foo();
typeof foo; // "object"
foo instanceof Foo; // true
Foo.prototype.isPrototypeOf(foo); // true
Run Code Online (Sandbox Code Playgroud)

返回对象时,从构造函数原型继承的新创建的对象将被丢弃:

function Foo () {
  return {};
}

var foo = new Foo();
typeof foo; // "object"
foo instanceof Foo; // false
Foo.prototype.isPrototypeOf(foo); // false
Run Code Online (Sandbox Code Playgroud)

也可以看看:


sla*_*ick 6

在这种情况下,当您返回一个新对象时没有区别.它可以改写为:

function Foo(x){
   this._x = x;
}

Foo.prototype.bar = function() { 
   return this._x;
}
Run Code Online (Sandbox Code Playgroud)

每次调用new Foo它时都会使用此语法创建一个属性为的新对象_x.好处是该bar函数将被存储一次并重用于Foo的多个实例.使用Foo()多次调用的问题中的代码将为每个实例创建一个条形函数.因此,将函数附加到原型而不是将它们直接放在对象上会使内存更轻松.

可以在MDC上找到原型工作方式的完整细分.