JavaScript中的'new'关键字是什么?

时间:2009-10-29 21:32:45

标签: javascript new-operator

JavaScript中的new关键字在第一次遇到时会非常混乱,因为人们倾向于认为JavaScript不是面向对象的编程语言。

  • 这是什么?
  • 它解决了什么问题?
  • 什么时候合适?什么时候不合适?

16 个答案:

答案 0 :(得分:2033)

它做了5件事:

  1. 它会创建一个新对象。该对象的类型只是 object
  2. 它将此新对象的内部,无法访问, [[prototype]] (即 __ proto __ )属性设置为构造函数的外部,可访问,原型< / em> object(每个函数对象都自动拥有 prototype 属性)。
  3. 它使this变量指向新创建的对象。
  4. 只要提到this,它就会使用新创建的对象执行构造函数。
  5. 它返回新创建的对象,除非构造函数返回非null对象引用。在这种情况下,将返回该对象引用。
  6. 注意:构造函数是指new关键字之后的函数,如

    new ConstructorFunction(arg1, arg2)
    

    完成此操作后,如果请求新对象的未定义属性,则脚本将检查对象的 [[prototype]] 对象。这就是你如何在JavaScript中获得类似于传统类继承的东西。

    关于这一点最困难的部分是第2点。每个对象(包括函数)都有一个名为 [[prototype]] 的内部属性。它可以在对象创建时设置,可以使用 new ,使用 Object.create ,也可以基于文字(函数默认为Function) .prototype,数字到Number.prototype等)。它只能用 Object.getPrototypeOf(someObject)读取。 有其他设置或读取此值的方法。

    除隐藏的 [[prototype]] 属性外,函数还有一个名为 prototype 的属性,您可以访问和修改此属性,为您创建的对象提供继承的属性和方法。


    以下是一个例子:

    ObjMaker = function() {this.a = 'first';};
    // ObjMaker is just a function, there's nothing special about it that makes 
    // it a constructor.
    
    ObjMaker.prototype.b = 'second';
    // like all functions, ObjMaker has an accessible prototype property that 
    // we can alter. I just added a property called 'b' to it. Like 
    // all objects, ObjMaker also has an inaccessible [[prototype]] property
    // that we can't do anything with
    
    obj1 = new ObjMaker();
    // 3 things just happened.
    // A new, empty object was created called obj1.  At first obj1 was the same
    // as {}. The [[prototype]] property of obj1 was then set to the current
    // object value of the ObjMaker.prototype (if ObjMaker.prototype is later
    // assigned a new object value, obj1's [[prototype]] will not change, but you
    // can alter the properties of ObjMaker.prototype to add to both the
    // prototype and [[prototype]]). The ObjMaker function was executed, with
    // obj1 in place of this... so obj1.a was set to 'first'.
    
    obj1.a;
    // returns 'first'
    obj1.b;
    // obj1 doesn't have a property called 'b', so JavaScript checks 
    // its [[prototype]]. Its [[prototype]] is the same as ObjMaker.prototype
    // ObjMaker.prototype has a property called 'b' with value 'second'
    // returns 'second'
    

    这就像类继承一样,因为现在,使用new ObjMaker()创建的任何对象也似乎都继承了'b'属性。

    如果您想要类似子类的东西,那么您可以这样做:

    SubObjMaker = function () {};
    SubObjMaker.prototype = new ObjMaker(); // note: this pattern is deprecated!
    // Because we used 'new', the [[prototype]] property of SubObjMaker.prototype
    // is now set to the object value of ObjMaker.prototype.
    // The modern way to do this is with Object.create(), which was added in ECMAScript 5:
    // SubObjMaker.prototype = Object.create(ObjMaker.prototype);
    
    SubObjMaker.prototype.c = 'third';  
    obj2 = new SubObjMaker();
    // [[prototype]] property of obj2 is now set to SubObjMaker.prototype
    // Remember that the [[prototype]] property of SubObjMaker.prototype
    // is ObjMaker.prototype. So now obj2 has a prototype chain!
    // obj2 ---> SubObjMaker.prototype ---> ObjMaker.prototype
    
    obj2.c;
    // returns 'third', from SubObjMaker.prototype
    
    obj2.b;
    // returns 'second', from ObjMaker.prototype
    
    obj2.a;
    // returns 'first', from SubObjMaker.prototype, because SubObjMaker.prototype 
    // was created with the ObjMaker function, which assigned a for us
    

    在最终找到this page之前,我读了很多关于这个主题的垃圾,其中很好地解释了这个问题。

答案 1 :(得分:372)

假设你有这个功能:

var Foo = function(){
  this.A = 1;
  this.B = 2;
};

如果您将其称为独立功能,请执行以下操作:

Foo();

执行此功能会向window对象(AB)添加两个属性。它将它添加到window,因为window是在执行它时调用函数的对象,函数中的this是调用函数的对象。至少在Javascript中。

现在,使用new调用它:

var bar = new Foo();

new添加到函数调用时会发生的情况是创建了一个新对象(仅var bar = new Object())并且函数中的this指向新Object你刚刚创建的,而不是调用函数的对象。因此,bar现在是一个包含属性AB的对象。任何函数都可以是构造函数,它并不总是有意义的。

答案 2 :(得分:155)

除了霍华德霍华德的回答,这是new做(或至少似乎做)的事情:

function New(func) {
    var res = {};
    if (func.prototype !== null) {
        res.__proto__ = func.prototype;
    }
    var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
    if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
        return ret;
    }
    return res;
}

虽然

var obj = New(A, 1, 2);

相当于

var obj = new A(1, 2);

答案 3 :(得分:97)

让初学者更好地理解

在浏览器控制台中试用以下代码。

count()

现在您可以阅读community wiki answer:)

答案 4 :(得分:33)

  

所以它可能不适合创作   对象的实例

它完全用于此。您可以像这样定义一个函数构造函数:

function Person(name) {
    this.name = name;
}

var john = new Person('John');

然而,ECMAScript带来的额外好处是你可以使用.prototype属性扩展,所以我们可以做类似......

Person.prototype.getName = function() { return this.name; }

从这个构造函数创建的所有对象现在都有getName,因为它们可以访问原型链。

答案 5 :(得分:26)

JavaScript 一种面向对象的编程语言,它完全用于创建实例。它是基于原型的,而不是基于类的,但这并不意味着它不是面向对象的。

答案 6 :(得分:13)

Javascript是一种动态编程语言,支持面向对象的编程范式,用于创建对象的新实例。

对象不需要类 - Javascript是prototype based语言。

答案 7 :(得分:4)

有时代码比单词更容易:

var func1 = function (x) { this.x = x; }                    // used with 'new' only
var func2 = function (x) { var z={}; z.x = x; return z; }   // used both ways
func1.prototype.y = 11;
func2.prototype.y = 12;

A1 = new func1(1);      // has A1.x  AND  A1.y
A2 =     func1(1);      // undefined ('this' refers to 'window')
B1 = new func2(2);      // has B1.x  ONLY
B2 =     func2(2);      // has B2.x  ONLY

对我来说,只要我没有原型,我就会使用func2的风格,因为它让我在函数内外有了更多的灵活性。

答案 8 :(得分:4)

已经有一些非常好的答案但是我发布了一个新答案,以强调我对下面 III 案例的观察,以及当你在一个函数中有一个明确的return语句时会发生什么是new。看看下面的案例:

案例I

var Foo = function(){
  this.A = 1; 
  this.B = 2;
};
console.log(Foo()); //prints undefined
console.log(window.A); //prints 1

上面是调用Foo指向的匿名函数的简单情况。当您调用此函数时,它将返回undefined。由于没有明确的return语句,因此JavaScript解释器在函数末尾强制插入return undefined;语句。这里的窗口是调用对象(上下文this),它获取新的AB属性。

案例II

var Foo = function(){
  this.A = 1;
  this.B = 2;
};
var bar = new Foo();
console.log(bar()); //illegal isn't pointing to a function but an object
console.log(bar.A); //prints 1

此处,JavaScript解释器看到new关键字会创建一个新对象,该对象充当this指向的匿名函数的调用对象(上下文Foo)。在这种情况下,AB成为新创建的对象的属性(代替窗口对象)。由于您没有任何显式的return语句,因此JavaScript解释器强制插入return语句以返回由于使用new关键字而创建的新对象。

案例III

var Foo = function(){
  this.A = 1;
  this.B = 2;
  return {C:20,D:30}; 
};
var bar = new Foo();
console.log(bar.C);//prints 20
console.log(bar.A); //prints undefined. bar is not pointing to the object which got created due to new keyword.

此处再次看到new关键字的JavaScript解释器创建了一个新对象,该对象充当this指向的匿名函数的调用对象(上下文Foo)。同样,AB成为新创建的对象的属性。但是这次你有一个明确的return语句,所以JavaScript解释器做任何自己的事情。

III 时需要注意的是,由于new关键字而创建的对象已从您的雷达中丢失。 bar实际上是指向一个完全不同的对象,该对象不是JavaScript解释器因new关键字而创建的对象。

答案 9 :(得分:4)

 " Every object (including functions) has this internal property called [[prototype]]" 

每个功能都有一个原型, 类型的对象,该对象会自动设置为使用该函数创建的对象的原型。

你们可以轻松检查:

const a = { name: "something" };
console.log(a.prototype); // undefined because it is not directly accessible

const b = function () {
  console.log("somethign");};

console.log(b.prototype); // returns b {}

但是每个函数和对象都有__proto__属性,该属性指向该对象或函数的原型。 __proto__prototype是2个不同的术语。我认为我们可以发表这样的评论:“每个对象都通过 proto 链接到原型”,但是__proto__在javascript中不存在。此属性是由浏览器添加的,仅用于调试。

console.log(a.__proto__); // returns {}
console.log(b.__proto__); // returns [Function]

你们可以在终端上轻松检查。那么什么是构造函数。

function CreateObject(name,age){
    this.name=name;
    this.age =age
}

首先要注意的三件事:

1-我们没有使用return关键字。 new将处理它。

2-函数名称大写,因此当开发人员看到您的代码时,他们可以理解他们必须使用new关键字。

3-我们不使用箭头功能。因为this参数的值是在创建箭头函数(即“窗口”)时获取的。箭头函数在词法上是作用域的,不是动态的。词汇在这里是指本地。箭头函数带有其本地“ this”值。

const me=new CreateObject("yilmaz","21")

new调用该函数,然后创建一个空对象{},然后添加值为“ name”的“ name”键和值为参数“ age”的“ age”键。

当我们调用一个函数时,会使用“ this”和“ arguments”创建一个新的执行上下文,这就是为什么“ new”可以访问这些参数。

默认情况下,构造函数中的该对象将指向“窗口”对象,但是new会对其进行更改。 “ this”指向创建的空对象{},然后将属性添加到新创建的对象。如果您定义的任何变量都没有“ this”属性,则不会将其添加到对象中。

function CreateObject(name,age){
    this.name=name;
    this.age =age;
    const myJob="developer"
}

myJob属性不会添加到该对象,因为没有任何引用指向新创建的对象。

   const me= {name:"yilmaz",age:21} // there is no myJob key

在一开始,我说每个函数都有“原型”属性,包括构造函数。我们可以将方法添加到构造函数的原型中,以便从该函数创建的每个对象都可以访问它。

 CreateObject.prototype.myActions=function(){ //define something}

现在“我”对象可以使用“ myActions”方法。

javascript具有内置的构造函数:Function,Boolean,Number,String ..

如果我创建

const a = new Number(5);
console.log(a);  // [Number: 5]
console.log(typeof a); // object

使用new创建的任何对象均具有对象类型。现在,“ a”可以访问存储在 Number.prototype 中的所有方法。如果我定义了

const b = 5;
console.log(a === b);//false

a和b为5,但a为宾语,b为基元。即使b是原始类型,创建后,javascript也会自动用Number()将其包装,因此b可以访问Number.prototype内部的所有方法。

当您要创建具有相同属性和方法的多个相似对象时,构造函数非常有用。这样,您就不会分配额外的内存,因此您的代码将更高效地运行。

答案 10 :(得分:2)

new关键字用于创建新对象实例。是的,javascript是一种动态编程语言,它支持面向对象的编程范例。关于对象命名的约定总是使用大写字母表示应该由new关键字实例化的对象。

obj = new Element();

答案 11 :(得分:2)

new关键字更改运行函数的上下文,并返回指向该上下文的指针。

如果不使用new关键字,则运行函数Vehicle()的上下文与调用Vehicle函数的上下文相同。 this关键字将引用相同的上下文。使用new Vehicle()时,会创建一个新的上下文,因此函数内的关键字this引用新的上下文。你得到的回报是新创建的上下文。

答案 12 :(得分:1)

每个JavaScript的JavaScript可能因平台而异,因为它始终是原始规范EcmaScript的实现。

在任何情况下,独立于实现,遵循EcmaScript规范权限的所有JavaScript实现都将为您提供面向对象的语言。根据ES标准:

  

ECMAScript是一种面向对象的编程语言   执行计算和操纵计算对象   在主机环境中。

现在我们已经同意JavaScript是EcmaScript的一个实现,因此它是一种面向对象的语言。任何面向对象语言中new操作的定义都表示,这种关键字用于从特定类型的类创建对象实例(包括匿名类型,例如C#)。

在EcmaScript中,我们不会使用类,因为您可以阅读规范:

  

ECMAScript不使用C ++,Smalltalk或Java等类。相反,可以以各种方式创建对象,包括via   一个文字符号或通过构造函数创建对象然后执行代码,通过分配初始化来初始化它们的全部或部分   值属性。每个构造函数都是一个函数   物业名称 -       原型‖用于实现基于原型的继承和共享属性。对象由
创建   在新表达式中使用构造函数;例如,新的   Date(2009,11)创建一个新的Date对象。调用构造函数   不使用new会产生依赖于构造函数的后果。   例如,Date()生成一个字符串表示形式   当前日期和时间而不是对象。

答案 13 :(得分:1)

Javascript不是面向对象的编程语言,因此 LOOK UP 过程 使用'DELEGATION PROCESS'(也称为原型委托或原型继承)进行javascript工作。

如果您尝试从不具有的对象中获取属性的值,则 JavaScript引擎查找对象的原型(及其原型,一次超过1步) 它是原型链,直到链结束直到 null ,即 Object.prototype == null (标准对象原型)。 此时,如果未定义属性或方法,则返回 undefined

因此,使用new关键字进行了一些手动完成的任务,例如

  1. 手动创建对象,例如newObj。
  2. 使用JS规范 [[prototype]] (即 proto < / strong>)
  3. 引用属性并将属性分配给newObj
  4. 返回newObj对象。

所有操作都是手动完成的。

function CreateObj(value1, value2) {
  const newObj = {};
  newObj.property1 = value1;
  newObj.property2 = value2;
  return newObj;
}
var obj = CreateObj(10,20);

obj.__proto__ === Object.prototype;              // true
Object.getPrototypeOf(obj) === Object.prototype // true

JavaScript关键字new可帮助自动执行此过程:

  1. 已创建由this:{}标识的新对象文字
  2. 引用属性并将属性分配给this
  3. 隐藏键创建 [[prototype]](即 proto 到Function.prototype共享空间。
  4. this对象{}的隐式返回
function CreateObj(value1, value2) {
  this.property1 = value1;
  this.property2 = value2;
}

var obj = new CreateObj(10,20);
obj.__proto__ === CreateObj.prototype             // true
Object.getPrototypeOf(obj) == CreateObj.prototype // true

不使用新关键字调用构造函数:

=> this: Window

function CreateObj(value1, value2) {
  var isWindowObj = this === window;
  console.log("Is Pointing to Window Object", isWindowObj);
  this.property1 = value1;
  this.property2 = value2;
}
var obj = new CreateObj(10,20); // Is Pointing to Window Object false
var obj = CreateObj(10,20); // Is Pointing to Window Object true
window.property1; // 10
window.property2; // 20

答案 14 :(得分:0)

new关键字使用函数作为构造函数创建对象的实例。例如:

var Foo = function() {};
Foo.prototype.bar = 'bar';

var foo = new Foo();
foo instanceof Foo; // true

实例继承自构造函数的prototype。所以给出上面的例子......

foo.bar; // 'bar'

答案 15 :(得分:0)

摘要:

new关键字在javascript中用于根据构造函数创建对象。 new关键字必须放在构造函数调用之前,它将执行以下操作:

  1. 创建一个新对象
  2. 将此对象的原型设置为构造函数的prototype属性
  3. this关键字绑定到新创建的对象并执行构造函数
  4. 返回新创建的对象

示例:

function Dog (age) {
  this.age = age;
}

const doggie = new Dog(12);

console.log(doggie);
console.log(doggie.__proto__ === Dog.prototype) // true

实际发生的情况:

  1. const doggie说:我们需要内存来声明变量。
  2. 分配操作符=说:我们将使用=之后的表达式来初始化此变量
  3. 表达式为new Dog(12)。 JS引擎看到了new关键字,创建了一个新对象,并将原型设置为Dog.prototype
  4. 在将this值设置为新对象的情况下执行构造函数。在此步骤中,将年龄分配给新创建的小狗对象。
  5. 新创建的对象被返回并分配给变量doggie。