JavaScript 中的new
关键字在第一次遇到时可能会非常混乱,因为人们倾向于认为 JavaScript 不是一种面向对象的编程语言。
- 它是什么?
- 它解决了哪些问题?
- 什么时候合适,什么时候不合适?
JavaScript 中的new
关键字在第一次遇到时可能会非常混乱,因为人们倾向于认为 JavaScript 不是一种面向对象的编程语言。
它做了 5 件事:
this
变量指向新创建的对象。this
每当提到时,它都会使用新创建的对象执行构造函数。null
对象引用。在这种情况下,将返回该对象引用。注意:构造函数是指new
关键字后面的函数,如
new ConstructorFunction(arg1, arg2)
完成此操作后,如果请求新对象的未定义属性,脚本将改为检查对象的[[prototype]]对象的属性。这就是在 JavaScript 中获得类似于传统类继承的方法。
最困难的部分是第 2 点。每个对象(包括函数)都有这个称为[[prototype]]的内部属性。它只能在对象创建时设置,可以使用new、Object.create或基于字面量(函数默认为 Function.prototype,数字为 Number.prototype 等)。它只能用Object.getPrototypeOf(someObject)读取。没有其他方法可以设置或读取此值。
函数,除了隐藏的[[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
在最终找到这个页面之前,我阅读了大量关于这个主题的垃圾,其中用漂亮的图表很好地解释了这一点。
假设你有这个功能:
var Foo = function(){
this.A = 1;
this.B = 2;
};
如果您将其称为独立函数,如下所示:
Foo();
执行此函数将为window
对象添加两个属性 (A
和B
)。它将它添加到,window
因为window
当你这样执行它时调用函数的对象,而this
在函数中是调用函数的对象。至少在 Javascript 中。
现在,这样称呼它new
:
var bar = new Foo();
添加到函数调用时会发生什么情况new
是创建了一个新对象(只是var bar = new Object()
),并且this
函数内的 指向Object
您刚刚创建的新对象,而不是指向调用该函数的对象。现在bar
是具有属性A
和的对象B
。任何函数都可以是构造函数,但这并不总是有意义的。
除了丹尼尔霍华德的回答,这里是什么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);
在浏览器控制台中尝试以下代码。
function Foo() {
return this;
}
var a = Foo(); //returns window object
var b = new Foo(); //returns empty object of foo
a instanceof Window; // true
a instanceof Foo; // false
b instanceof Window; // false
b instanceof Foo; // true
现在您可以阅读社区 wiki 答案:)
所以它可能不是用于创建对象的实例
它正是为此而使用的。您定义一个函数构造函数,如下所示:
function Person(name) {
this.name = name;
}
var john = new Person('John');
然而,ECMAScript 的额外好处是您可以使用该.prototype
属性进行扩展,因此我们可以执行类似...
Person.prototype.getName = function() { return this.name; }
从这个构造函数创建的所有对象现在都将拥有一个getName
因为它们可以访问的原型链。
JavaScript是一种面向对象的编程语言,它完全用于创建实例。它是基于原型的,而不是基于类的,但这并不意味着它不是面向对象的。
该new
关键字在 javascript 中用于从构造函数创建对象。new
关键字必须放在构造函数调用之前,并将执行以下操作:
this
到新创建的对象并执行构造函数function Dog (age) {
this.age = age;
}
const doggie = new Dog(12);
console.log(doggie);
console.log(Object.getPrototypeOf(doggie) === Dog.prototype) // true
究竟会发生什么:
const doggie
说:我们需要内存来声明一个变量。=
说:我们将用下面的表达式初始化这个变量=
new Dog(12)
。JS 引擎看到 new 关键字,创建一个新对象并将原型设置为 Dog.prototypethis
设置为新对象的值执行。在这一步中,年龄被分配给新创建的小狗对象。已经有一些非常棒的答案,但我发布了一个新答案,以强调我对下面案例III的观察,即当您正在调用的函数中有明确的 return 语句时会发生什么new
。看看下面的案例:
案例一:
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;
在函数末尾插入一条语句。这里 window 是this
获取新属性A
的调用对象(上下文)。B
案例二:
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
。在这种情况下A
,并B
成为新创建的对象的属性(代替窗口对象)。由于您没有任何明确的 return 语句,因此 JavaScript 解释器强制插入 return 语句以返回由于使用new
关键字而创建的新对象。
案例三:
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
。再次,A
成为B
新创建对象的属性。但是这次你有一个明确的 return 语句,所以 JavaScript 解释器不会自己做任何事情。
在情况III中要注意的是,由于new
关键字而创建的对象从您的雷达中丢失了。bar
实际上是指向一个完全不同的对象,它不是 JavaScript 解释器由于new
关键字而创建的对象。
引用 JavaScripit 中的 David Flanagan:权威指南(第 6 版),Ch。4,第 62 页:
当对象创建表达式被求值时,JavaScript 首先创建一个新的空对象,就像对象初始化器 {} 创建的对象一样。接下来,它使用指定的参数调用指定的函数,将新对象作为 this 关键字的值传递。然后该函数可以使用它来初始化新创建对象的属性。为用作构造函数而编写的函数不返回值,对象创建表达式的值是新创建和初始化的对象。如果构造函数确实返回了对象值,则该值将成为对象创建表达式的值,并且新创建的对象将被丢弃。
---附加信息---
上述案例代码片段中使用的函数在 JS 世界中具有特殊名称,如下所示:
案例 I 和 II - 构造函数
案例 III - 工厂功能。工厂函数不应该与new
我用来解释当前线程中的概念的关键字一起使用。
您可以在此线程中了解它们之间的区别。
Javascript 是一种动态编程语言,它支持面向对象的编程范式,用于创建对象的新实例。
对象不需要类 - Javascript 是一种基于原型的语言。
new
关键字更改函数正在运行的上下文并返回指向该上下文的指针。
当您不使用new
关键字时,函数Vehicle()
运行的上下文与您调用Vehicle
函数的上下文相同。关键字将this
引用相同的上下文。使用 时new Vehicle()
,会创建一个新上下文,因此函数内的关键字this
指的是新上下文。你得到的回报是新创建的上下文。
有时代码比文字更容易:
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 的风格,因为它在函数内部和外部给了我更多的灵活性。
" 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__
在 javascript 中不存在。浏览器添加此属性只是为了帮助调试。
console.log(a.__proto__); // returns {}
console.log(b.__proto__); // returns [Function]
你们可以在终端上轻松查看。那么什么是构造函数。
function CreateObject(name,age){
this.name=name;
this.age =age
}
首先要注意的5件事:
1- 当使用 调用构造函数时new
,会调用函数内部的 [[Construct]] 方法来创建新的实例对象并分配内存。
2-我们没有使用return
关键字。new
会处理它。
3- 函数名称大写,因此当开发人员看到您的代码时,他们可以理解他们必须使用new
关键字。
4-我们不使用箭头功能。因为this
参数的值是在创建箭头函数的那一刻被拾取的,即“窗口”。箭头函数是词法范围的,而不是动态的。这里的词汇意味着本地。箭头函数带有其本地“this”值。
5- 与常规函数不同,箭头函数永远不能使用 new 关键字调用,因为它们没有 [[Construct]] 方法。箭头函数也不存在原型属性。
const me=new CreateObject("yilmaz","21")
new
调用该函数,然后创建一个空对象 {},然后添加具有“name”值的“name”键,以及具有参数“age”值的“age”键。
当我们调用一个函数时,会使用“this”和“arguments”创建一个新的执行上下文,这就是“new”可以访问这些参数的原因。
默认情况下,构造函数内部的 this 将指向“window”对象,但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 中的所有方法。
当您想要创建具有相同属性和方法的多个相似对象时,构造函数很有用。这样您就不会分配额外的内存,因此您的代码将更有效地运行。
new
关键字用于创建新的对象实例。是的,javascript 是一种动态编程语言,它支持面向对象的编程范式。关于对象命名的约定是,对于应该由 new 关键字实例化的对象,始终使用大写字母。
obj = new Element();
new
关键字使用函数作为构造函数创建对象的实例。例如:
var Foo = function() {};
Foo.prototype.bar = 'bar';
var foo = new Foo();
foo instanceof Foo; // true
实例继承自prototype
构造函数。所以给出上面的例子......
foo.bar; // 'bar'
好吧,JavaScript per si 可能因平台而异,因为它始终是原始规范 EcmaScript 的实现。
在任何情况下,独立于实现,所有遵循 EcmaScript 规范的 JavaScript 实现都会为您提供面向对象的语言。根据 ES 标准:
ECMAScript 是一种面向对象的编程语言,用于在主机环境中执行计算和操作计算对象。
所以现在我们已经同意 JavaScript 是 EcmaScript 的实现,因此它是一种面向对象的语言。任何面向对象语言中的操作定义都new
表示,此类关键字用于从某种类型的类(包括匿名类型,在 C# 等情况下)创建对象实例。
在 EcmaScript 中,我们不使用类,您可以从规范中阅读:
ECMAScript 不使用 C++、Smalltalk 或 Java 中的类。相反,可以通过各种方式创建对象,包括通过文字符号或通过构造函数创建对象,然后执行代码,通过将初始值分配给它们的属性来初始化它们的全部或部分。每个构造函数都是一个函数,具有一个名为“原型”的属性,用于实现基于原型的继承和共享属性。对象是通过
在 new 表达式中使用构造函数来创建的;例如, new Date(2009,11) 创建一个新的 Date 对象。在不使用 new 的情况下调用构造函数会产生依赖于构造函数的后果。例如,Date() 生成当前日期和时间的字符串表示,而不是对象。
Javascript 不是面向对象的编程 (OOP) 语言,因此 javascript 中的LOOK UP过程使用“委托过程”,也称为原型委托或原型继承。
如果您尝试从一个对象中获取属性的值,但它没有,JavaScript 引擎会查看对象的原型(及其原型,一次上一步),它是原型链,直到链结束为null是Object.prototype == null(标准对象原型)。此时,如果未定义属性或方法,则返回未定义。
因此,使用new
关键字一些手动完成的任务,例如
newObj
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
有助于自动化此过程:
this:{}
this
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
在没有 new 关键字的情况下调用构造函数:
=> 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