在另一个问题中,一个用户指出,new关键字的使用是危险的,并提出了一个不使用new的对象创建解决方案。我不相信这是真的,主要是因为我使用了原型、脚本库和其他优秀的JavaScript库,而且每个库都使用了new关键字。
尽管如此,昨天我在Yui剧院看了道格拉斯·克罗克福德的演讲,他说的完全一样,他在他的代码中不再使用new关键字(crockford on javascript-Act III:Function t he Ultimate-50:23分钟)。
使用new关键字是否"坏"?使用它的优点和缺点是什么?
- 使用这个新的关键字也不错。但如果忘记了它,您将作为常规函数调用对象构造函数。如果构造函数没有检查其执行上下文,那么它不会注意到"this"指向不同的对象(通常是全局对象)而不是新实例。因此,构造函数将向全局对象(窗口)添加属性和方法。如果您总是检查"this"是否是对象函数中对象的实例,那么您将永远不会遇到此问题。
- 我不明白。一方面,道格不鼓励使用new。但是当你看到Yui图书馆的时候。你必须在任何地方使用new。如var myDataSource = new Y.DataSource.IO({source:"./myScript.php"}); 。
- @Aditya_Gaur,这是因为如果您需要初始化一个对象,那么如果您使用Object.create方法并在之后调用它,那么就必须对init方法进行黑客处理。更容易使用new,它可以同时使用这两种方法,设置原型链并调用一些初始值设定项代码。
- 我认为这不应该关闭。是的,它可能会激发一些克罗克福德反扇毒液,但我们谈论的是流行的建议,以基本上避免一个主要的语言功能在这里。使每个jquery对象几乎不重(涉及内存的地方)的机制涉及使用"new"关键字。喜欢使用工厂方法而不是不断地调用新的方法,但不要只使用对象文本来大幅降低体系结构选项和性能潜力。他们有自己的位置,施工人员也有自己的位置。这是老生常谈的糟糕建议。
- 拒绝不从对象函数继承的执行上下文不是一种明智的方法。然后,您打破了诸如.call和.apply等关键功能。
- TLDR:使用new并不危险。省略new是危险的,因此很糟糕。但是在ES5中,您可以使用严格的模式,它可以保护您免受这种危险和其他许多危险。
- 不具建设性:503人不同意…
- 现在是530。该死的,摩兹。
Crockford在推广优秀的JavaScript技术方面做了很多工作。他对语言的关键要素的固执己见引起了许多有益的讨论。也就是说,太多的人把每一个"坏"或"坏"的宣言当作福音,拒绝超越一个人的观点。有时候会有点沮丧。
与从头构建每个对象相比,使用new关键字提供的功能有几个优势:
原型继承。虽然经常被那些习惯于基于类的OO语言的人所怀疑和嘲笑,但javascript的本地继承技术是一种简单而有效的代码重用方法。新的关键字是使用它的规范(并且只有跨平台可用)方法。
性能。这是1的副作用:如果我想为我创建的每个对象添加10个方法,我可以编写一个创建函数,手动将每个方法分配给每个新对象…或者,我可以将它们分配给创建函数的prototype,并使用new来消除新对象。这不仅速度更快(原型上的每个方法都不需要代码),而且避免了使用每个方法的单独属性对每个对象进行膨胀。在创建许多对象时,在速度较慢的计算机(尤其是速度较慢的JS解释器)上,这意味着可以显著节省时间和内存。
是的,new有一个关键的缺点,可以用其他答案来描述:如果你忘记使用它,你的代码将在没有警告的情况下中断。幸运的是,这种缺点很容易减轻——只需向函数本身添加一点代码:
1 2 3 4 5 6 7 8 9
| function foo()
{
// if user accidentally omits the new keyword, this will
// silently correct the problem...
if ( !(this instanceof foo) )
return new foo();
// constructor logic follows...
} |
现在,您可以使用new的优点,而不必担心意外误用造成的问题。你甚至可以在检查中添加一个断言,如果一想到死掉的代码会让你感到不安的话。或者,正如一些人所说,使用检查引入运行时异常:
1 2
| if ( !(this instanceof arguments.callee) )
throw new Error("Constructor called as a function"); |
(请注意,此代码段能够避免对构造函数函数名进行硬编码,因为与前面的示例不同,它不需要实际实例化对象-因此,可以将其复制到每个目标函数中,而无需修改。)
JohnResig在他的简单的"类"实例化帖子中详细介绍了这一技术,并在默认情况下将这种行为构建到您的"类"中。绝对值得一读…正如他即将出版的书《Javascript忍者的秘密》一样,这本书在Javascript语言的这个和许多其他"有害"特性中找到了隐藏的黄金(关于EDOCX1的章节〔5〕对我们这些最初把这个备受非议的特性视为一种诡计的人特别有启发性)。
- 如果(!)(this instanceof arguments.callee))引发错误("constructor called as a function");//更一般,不需要知道构造函数的名称,让用户修复代码。
- 一些人:是的!如果您能够测试和纠正客户机代码,那么这将是一个很好的选择。
- @Shog9,谢谢-非常好的评论(学到了一些新的东西)!
- Shog你能编辑一下答案并详细介绍一下你提到的"新"的优点吗(速度和原型的充分利用)?我相信这是最正确的答案,我会把它标记为接受的答案,只要这些事情解释得多一点。谢谢)
- @ Pablo -完成了。也就是说,我不确定你是否应该接受这里的答案;当然,这取决于你自己,但这似乎有点主观的讨论。
- 问题是使用新关键字是否"坏",以及它的优缺点。我相信你的回答能以非常完整和简洁的方式解释这一点。我接受它。
- 关于检查,您不能假定全局对象是window,然后执行if(this==window)throw.。
- @meandmycode:你可以假设。但如果window由于某种原因不是全球的目标,它就会破裂…或者如果this引用了其他上下文。另外,对于一个例子来说,它有点分散注意力,因为测试的重点(无论是隐式的还是显式的)是验证上下文对象是否是构造函数本身的实例。
- 唯一的原因是arguments.Callee是一个"昂贵的"调用。我想知道是否有更好的方法来更一般地进行检查。另外,我认为在全局对象之外的其他对象上初始化是有意的,而不是错误的。
- 如果你担心性能——而且实际上有理由这样做——那就根本不要做检查。要么记住使用new,要么使用包装函数来记住它。我怀疑,如果你正处在关键时刻,你已经用尽了其他的优化方法,比如memoization,所以你的创建调用将被本地化…
- 当然,我理解关于过早优化的要点,当使用变为304ms的被调用方时,需要多次迭代来显示显著的开销,"100000"函数调用只会中断1毫秒。虽然代价非常昂贵,但它可能完全与呼叫主体无关,以及在给定时间段内实际发生呼叫的次数。
- 很高兴能把它变成+50-理性的论据,在这里把你想要的所有问题都解决了。
- @讽刺的是,有些人不应该是"新错误"?
- @BZlm:有趣的是,这实际上并不重要——Error()和new Error()都返回Error的实例。然而,考虑到上下文…真有趣。
- 哦,哈哈!从来没有看到过那一个粉碎!但是:ECMA-262,第5版,15.11.1错误构造函数作为函数调用:当错误作为函数而不是构造函数调用时,它创建并初始化一个新的错误对象。因此,函数调用错误(…)相当于具有相同参数的对象创建表达式new error(…)。
- 使用arguments.callee来检查是否使用new调用过,可能不是很好,因为arguments.callee在严格模式下不可用。最好使用函数名。
- 如果我拼错了一个标识符,我的代码就会中断。我不应该使用标识符吗?不使用new,因为您可以忘记用代码编写它,这和我的示例一样荒谬。
- @意思是"不",你不能100%假设它是window。如果在服务器端使用它,它就不会是窗口。使用call和apply可以用其他任何方法调用函数this,因此正确的测试是看它是否是构造函数的一个实例
- 我使用的一个有用的惯例(我认为它来自克罗克福德本人):如果它需要"新的",像类名一样大写它。x = new Foo();与常规函数x = foo();的比较
- 如果启用严格模式,如果忘记使用新的,则在尝试使用时将得到一个异常:yuiblog.com/blog/2010/12/14/strict-mode-is-coming-town,这比向每个构造函数添加检查实例更容易。
- 如果返回一个self变量而不是this,并将第一个示例更改为var self = this instanceof foo ? this : new foo();,那么这将在允许foo() instanceof foo返回真值的同时使用变量函数。
- 这将禁止任何人在mixin等中使用构造函数。最好检查"this"不等于全局对象。(function(ctx) {if (this === ctx) throw new Error("don't call as function");})(this);
- 这方面的更新可能会有用,至少我感兴趣
- post忽略的是,由于ES5,存在Object.create(),因此原因1&2不再适用。
- 说真的,@cerved…虽然我个人也会避免将Object.create()放在各处,甚至比new更重要,但您可能希望限制创建非平凡对象的位置以避免错误,特别是如果您有许多依赖于初始化的方法。new的真正危险总是它看起来比原来更安全;object.create看起来很低级和"危险",但实际上也是一样的。
- @有些"EcmaScript(ES5)的第五版禁止在严格模式下使用arguments.callee()"。
- @自我写这篇评论以来的10年里,JRH的一些事情发生了变化。10年前,当时有效的是1999年的ES3。ES5于一年后,即2009年12月出版(正如我在回答这个问题时提到的)。我不允许编辑我10年前的评论,我很抱歉当时我看不到未来,看到它会改变。我仍然无法预测未来。
- @是的,我知道你不能编辑它;也许删除它并发表新的评论?
- 如果我们要更新这个@jrh,在答案中更值得注意的是ES6通过class将这个模式构建到语言本身中,并检查是否有新的更少的调用会引发错误。也许我会去的。
- @Shog9很好。如果你有机会的话,我想这样的更新会很有帮助。
- @JRH号。它在正常模式下仍然有效。评论已经提到了ES5。在严格模式下,没有理由使用arguments.callee。我不想抹去所有对历史的引用。
- @一些可以的;取决于你
我刚刚读了他的藏书《javascript:好的部分》的一些部分。我觉得他认为所有咬过他的东西都是有害的:
关于开关坠落:
I never allow switch cases to fall
through to the next case. I once found
a bug in my code caused by an
unintended fall through immediately
after having made a vigorous speech
about why fall through was sometimes
useful. (page 97, ISBN
978-0-596-51774-8)
关于++和
The ++ (increment) and -- (decrement)
operators have been known to
contribute to bad code by encouraging
exessive trickiness. They are second
only to faulty architecture in
enabling viruses and other security
menaces. (page 122)
关于新的:
If you forget to include the new
prefix when calling a constructor
function, then this will not be
bound to the new object. Sadly, this
will be bound to the global object, so
instead of augmenting your new object,
you will be clobbering global
variables. That is really bad. There
is no compile warning, and there is no
runtime warning. (page 49)
还有很多,但我希望你能拍到照片。
我对你的问题的回答是:不,这是无害的。但是如果你忘了在应该使用的时候使用它,你可能会遇到一些问题。如果你在一个良好的环境中发展,你会注意到这一点。
更新
在这个答案写完一年后,第五版EcmaScript发布了,支持严格模式。在严格模式下,this不再与全局对象绑定,而是与undefined绑定。
- 我完全同意。解决方案:始终记录用户必须如何实例化对象。使用一个示例,用户可能会剪切/粘贴。每种语言中都有可能被误用的结构/特性,从而导致异常/意外的行为。它不会使它们有害。
- 有一种惯例,总是以大写字母开始构造函数,而所有其他函数则以小写字母开始。
- 我刚意识到克罗克福德不认为有害…我不知道我创建了多少次不定式循环,因为我忘记了递增一个变量…
- 考虑到两种同等的方法,你会选择更危险的方法,仅仅是因为你可以?
- @格雷格·迪恩:那不是我说的。我不认为新的有害,也不继续,++,--,==,!=和标签,用于,while和switch。
- 问题不在于新事物是否有害。这是关于它的缺点/优点。有一个显著的缺点,即当忽略新的模式时,依赖它的构建模式可能有害。
- 正如佩兹所指出的,这一点的优势在于,它可能更清晰、更家庭化。
- ++,--也一样。他们用最清晰的语言准确地表达了我的意图。我爱他们!有些人可能很清楚,但我已经厌倦了。当它们更清晰的时候我就用它们(双关语,无法抗拒)。
- 我对克罗克福德的回答是:编程很难,我们去购物吧。谢斯!
- 说得很好,先生,说得很好。Crockford的"天空坠落"方法对JS没有任何帮助。
- 我还没读他的书。但我认为你应该从错误中吸取教训。如果++咬了他,那么对他来说避免++是对的。当然,我完全赞成丰田章男的"五个为什么",所以我可能会更深入地挖掘,找出它为什么真的咬我。
- 从第112页起:"递增和递减操作符使得以非常简洁的方式编写成为可能。在C等语言中,它们可以编写一行代码来复制字符串:"(续…)
- 对于(P=SRC,Q=DEST;!*p;p++,q++)*q=*p;"它们还鼓励一种编程风格,事实证明,这种风格是鲁莽的。造成严重安全漏洞的大多数缓冲区溢出错误都是由这样的代码造成的。"
- 我不同意克罗克福德所说的某些部分,也同意其他一些部分,比如埃瓦尔。
- stackoverflow.com/questions/197769/…
- 是啊。我喜欢那里公认的答案,当讨论"邪恶"的特征时,请记住这一点。;-)
- 好编程的一部分是编写易于维护的代码,特别是由经验不足的开发人员编写的代码。即使你确定你永远不会忘记使用new(在这种情况下,你比我更自信),你确定你的整个团队都不会犯这种错误吗?我也认为克罗克福德有点过于谨慎,但这是一个我绝对同意他的地方。
- @Justinmorgan自从答案6年前写出来以来,发生了很多事情,例如,我们现在有了EDOCX1(见我的答案更新),如果没有在预期的时候使用new,那么this将是undefined,而不是全局对象,因此如果使用了它,您将得到一个例外。我忘记了使用new,用while创建了无限循环,在switch中忘记了break,调用了参数错误或顺序错误的函数以及一大堆其他错误……但大多数错误是在测试代码或beta测试时发现的。
- 我没有读过他的书,但是我100%同意克罗克福德的观点,你提到的那些特定的语言特性会导致问题,在设计语言时可以避免,因此是"坏的"。尤其是我一直讨厌的。我的意思是,自从我忘记了一个"中断"已经有好几年了,也许几十年了,但我讨厌它是多么冗长的代码。事后看来,C可能做了相反的事情——添加了一个关键字,当你想进入下一个案例时使用它——然后所有随后的语言都会模仿它。太干净了:)
- fwiw,作为一个经常使用C语言的人,我不喜欢for(p = src, q= dest; !*p; p++, q++) *q=*p;,但这并不是我通常使用的方式。我可以想到很多无害的情况,其中i++和i--不可能造成任何伤害,而且非常清楚;而且它不像i+=1或i = i + 1那样好得多。我认为道格用+和-做了太多的概括。不过,我同意他关于以东十一〔八〕倒台的看法。
JavaScript是一种动态语言,有无数种方法可以让其他语言阻止你。
避免一个基本的语言功能,如new的基础上,你可能会搞砸,这有点像在穿过雷区前脱下你闪亮的新鞋,以防你的鞋弄脏。
我使用的惯例是函数名以小写字母开头,而实际上是类定义的"函数"则以大写字母开头。结果是一个非常引人注目的视觉线索,表明"语法"是错误的:
1
| var o = MyClass(); // this is clearly wrong. |
除此之外,良好的命名习惯还有帮助。在所有函数都做了一些事情之后,它的名称中应该有一个动词,而类代表对象,是没有动词的名词和形容词。
1 2
| var o = chair() // Executing chair is daft.
var o = createChair() // makes sense. |
有趣的是,So的语法着色解释了上面的代码。
- 是的,我只是在想语法着色的问题。
- 有一次我忘了打"函数"这个词。这个词应该不惜一切代价加以避免。还有一次我在多行if/then语句中没有使用大括号。所以现在我不用大括号,只写一行条件。
- "这显然是错误的"。为什么?对于我的类(只做if (! this instanceof MyClass) return new MyClass()),我实际上更喜欢new无语法。为什么?因为函数比构造函数更通用。省略new可以很容易地将构造函数改为正则函数…或者反过来。添加new使代码比需要的更具体。因此灵活性较差。与Java相比,它建议接受EDCOX1,21,而不是EDCOX1,22,因此调用方可以选择实现。
我是Javascript的新手,所以也许我在提供一个好的观点方面没有太多经验。然而,我想分享我对这个"新"事物的看法。
我来自C世界,在那里使用关键字"new"是很自然的,以至于我觉得工厂设计模式很奇怪。
当我第一次用javascript编写代码时,我没有意识到有"new"关键字和类似于yui模式的代码,我很快就会遇到灾难。当回顾我编写的代码时,我会忘记一行代码应该做什么。更混乱的是,当我"干运行"代码时,我的思想不能真正地在对象实例边界之间转换。
然后,我找到了"new"关键字,对我来说,它是"separate"的东西。使用新的关键字,它可以创建一些东西。如果没有新的关键字,我知道我不会把它与创建东西混淆,除非我调用的函数给了我有力的线索。
例如,对于var bar=foo();,我没有任何线索,因为什么条可能是……它是返回值还是新创建的对象?但对于var bar = new foo();,我确信酒吧是一个目标。
- 同意,我认为工厂模式应该遵循像makefoo()这样的命名约定。
- +"新"的出现更清楚地说明了意图。
- 当JS中的几乎所有内容都是一个对象时,这种响应有点奇怪。当所有函数都是对象时,为什么需要确定函数是对象?
- @Joshuaramirez重点不是typeof new foo() =="object"。是new返回foo的一个实例,你知道你可以调用foo.bar()和foo.bang()。但是,通过使用jsdoc的@return可以很容易地减轻这一点,而不是我所提倡的过程代码(避免使用new)。
- @胡安门德斯嗯…你的文章让我觉得你喜欢新的,因为它在你的代码库中有明确的关键字。我能理解。这就是我使用模块模式的原因。我将有一个名为createfoo、newfoo或makefoo的函数,只要它是显式的,就没关系。在里面,我声明变量,这些变量在从函数返回的对象文本中用作闭包。这个对象文字最终成为了你的对象,而这个函数只是一个构造函数。
另一个新的例子是我称之为pooh编码。小熊维尼跟着他的肚子。我说用你用的语言去做,而不是反对它。
这种语言的维护者很有可能会优化语言,使之适合他们想要鼓励的习语。如果他们在语言中加入一个新的关键字,他们可能会认为在创建一个新的实例时要清楚是有意义的。
遵循语言意图编写的代码在每次发布时都会提高效率。避免使用该语言的关键结构的代码将随着时间的推移而受到影响。
编辑:这远远超出了性能。我数不清我听到(或说)"他们为什么要那样做?"当发现奇怪的代码时。通常情况下,在编写代码时,有一些"好"的理由。遵循语言之道是你最好的保险,因为几年后你的代码就不会被嘲笑了。
- +1关于pooh编码链接-现在我需要找借口在我的对话中解决这个问题…
- 大声笑!我在这一领域有多年的经验,我可以向你保证,你不会遇到任何困难。他们经常在robowiki.net上叫我pooh。=)
- 不知道你是否会看到这个评论,但是那个pooh编码链接已经死了。
- 谢谢你的提醒。上周,我们将robowiki.net迁移到了一个新的wiki上,现在无法访问旧的内容。我会尽快使那些旧链接工作。
我写了一篇关于如何减轻在没有新关键字的情况下调用构造函数的问题的文章。它主要是说教性的,但它展示了如何创建使用或不使用new的构造函数,并且不需要添加样板代码来测试每个构造函数中的this。
http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html
技术要点如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| /**
* Wraps the passed in constructor so it works with
* or without the new keyword
* @param {Function} realCtor The constructor function.
* Note that this is going to be wrapped
* and should not be used directly
*/
function ctor(realCtor){
// This is going to be the actual constructor
return function wrapperCtor(){
var obj; // object that will be created
if (this instanceof wrapperCtor) {
// Called with new
obj = this;
} else {
// Called without new. Create an empty object of the
// correct type without running that constructor
surrogateCtor.prototype = wrapperCtor.prototype;
obj = new surrogateCtor();
}
// Call the real constructor function
realCtor.apply(obj, arguments);
return obj;
}
function surrogateCtor() {}
} |
以下是如何使用它:
1 2 3 4 5 6 7 8 9 10
| // Create our point constructor
Point = ctor(function(x,y){
this.x = x;
this.y = y;
});
// This is good
var pt = new Point(20,30);
// This is OK also
var pt2 = Point(20,30); |
- 避开arguments.callee真是太棒了!
- surrogateConstructor应为surrogateCtor(反之亦然)。
- 我维护了一个类似的由Crockford启发的实用程序的集合,发现当我开始一个新项目时,它总是让我运行来查找实现。这包含了编程的一个基本部分:对象实例化。所有这些工作,仅仅是为了启用Happhazard实例化代码?老实说,我很欣赏这个包装器的独创性,但它似乎只是造成了不小心的编码。
- @JoeCoder我提到这只是为了教学目的,我不赞成这种偏执的编码方式。但是,如果我正在编写类库,那么是的,我将以对调用者透明的方式添加这个特性。
不使用新关键字的原因很简单:
完全不使用它,可以避免意外忽略它带来的陷阱。Yui使用的构造模式是如何完全避免使用新关键字的一个例子。"
1 2 3 4 5
| var foo = function () {
var pub= { };
return pub;
}
var bar = foo(); |
或者你可以这样做:
1 2
| function foo() { }
var bar = new foo(); |
但是这样做的话,你就有可能有人忘记使用新的关键字,而这个操作符就是fubar。阿法克这样做没有好处(除了你已经习惯了)。
在一天结束的时候:这是关于防御性的。你能用新的说法吗?对。这会使您的代码更危险吗?对.
如果您曾经编写过C++,那么在删除指针后,将指针设置为null是类似的。
- 这两段代码完全等效吗?
- 不。使用"new foo()"时,会在返回的对象上设置一些属性,如构造函数。
- 同样,为了简洁起见,我省略了任何初始化。
- 所以,只是要澄清一下:你不应该使用"新的",因为你可能会忘记它?你在开玩笑吧?
- @在其他语言中,忘记"新"会导致错误。在Javascript中,它只是继续进行卡车运输。你可以忘记,却永远不会意识到。简单地看一看错误的代码根本就不清楚出了什么问题。
- @格雷格:我不知道第一种技术是如何允许使用原型链的——对象文本是很好的,但是出于恐惧而放弃原型所提供的性能和其他优势似乎有点傻。
- @炸弹-你应该使用"新"因为你(和任何使用你的代码的人)永远不会犯错误?你在开玩笑吧?
- @Shog-很好,John Resig链接也是+1
- 谢谢格雷格,我想我知道为什么当我看到这个问题的时候,我凭直觉站在了新的一边。我总是很无礼。不管那些工程师怎么说,玻璃是半满的。
- 如果我理解这一点,那么您是否应该使用new并不是真正的问题,而是您是否应该编写构造函数,以便用new调用它们。对吗?
- 如果您对构造函数使用了大写字母(为了直观区分,无论如何都建议使用大写字母),静态检查无效的构造函数调用(缺少新的)很简单。例如,jshint为此使用newcap(设置为true)。考虑到这个简单的"编译时"检查,我认为没有理由禁止新的。
- @肯特弗雷德里克这就像不使用==,因为如果我们使用=,它将导致一个无声的错误。
- @Gregdean对这样一个迟来的评论感到抱歉,但是一个linting工具比用偏执的检查乱扔代码要好得多,正如Matthew Flaschen提到的。
我认为"新"增加了代码的清晰度。清晰是值得的。很高兴知道有陷阱,但通过避免清晰来避免它们对我来说似乎不是一种方式。
案例1:
new不是必需的,应该避免。
1 2 3 4 5
| var str = new String('asd'); // type: object
var str = String('asd'); // type: string
var num = new Number(12); // type: object
var num = Number(12); // type: number |
案例二:需要new,否则会出错
1 2
| new Date().getFullYear(); // correct, returns the current year, i.e. 2010
Date().getFullYear(); // invalid, returns an error |
- 需要注意的是,在案例1中,仅当您打算进行类型转换(并且不知道hull对象是否有转换方法,如toString())时才将构造函数作为函数调用是有意义的。在所有其他情况下,使用文字。不是String('asd'),而是简单的'asd',不是Number(12),而是简单的12。
- @指出这条规则的一个例外是Array:Array(5).fill(0)比[undefined, undefined, undefined, undefined, undefined].fill(0)和(var arr = []).length = 5; arr.fill(0);更容易阅读。
- @Yoyonny我的陈述是在答案的案例1的上下文中做出的,它指的是对与基元类型对应的对象类型使用new和构造函数。您建议的字面意思不等同于Array调用(尝试0 in …,其余的是语法错误:)否则您是正确的,尽管应该注意,如果您认为不一致的实现(因此是一个模拟的Array.prototype.fill(…),Array(5)可能是不明确的。
下面是我对支持和反对使用new运算符的两个最有力的论点所作的最简要的总结:
反对
new的论点
功能设计为使用new运营商可能造成灾难性后果。不正确的影响作为普通函数调用。一在这种情况下,函数的代码将在以下范围内执行:调用函数,而不是本地对象的作用域有意的。这可能导致全球要获取的变量和属性被灾难覆盖后果。
最后,写了function Func(),然后打电话给Func.prototype。在里面加入一些东西可以调用new Func()来构造你的东西对某些人来说很难看希望使用的程序员对象继承的另一种样式建筑和风格原因。
关于这个论点的更多信息,请看道格拉斯·克罗克福德的伟大而简明的书《javascript:好的部分》。事实上,还是去看看吧。
支持
new的论点
同时使用new运算符原型分配很快。
关于意外的事情运行构造函数函数的全局命名空间中的代码可以如果你总是在您的要检查的构造函数函数看看是否有人打电话给他们正确,并且在以下情况下他们没有,处理电话根据需要适当。
关于这种技术的简单解释,以及他所提倡的继承模型的一般更深入的解释,请参阅约翰·雷西格的文章。
- 对反对论点的更新:1可以通过使用'use strict';模式(或链接中的方法)来缓解2在ES6中具有同态糖,但是行为与以前相同。
我同意佩兹和这里的一些人。
在我看来,"新"显然是自我描述的对象创造,格雷格·迪恩描述的Yui模式被完全掩盖了。
有人可能在baz不是对象创建方法的地方编写var bar = foo;或var bar = baz();,这看起来危险得多。
我认为新语言是邪恶的,不是因为如果你忘记了错误地使用它,它可能会导致问题,而是因为它破坏了继承链,使语言更难理解。
JavaScript是基于原型的面向对象的。因此,每个对象都必须从另一个对象(如var newObj=Object.create(oldObj))创建。这里,oldobj被称为newobj的原型(因此称为"基于原型")。这意味着,如果在newobj中找不到属性,则将在oldobj中搜索该属性。因此,默认情况下,newobj将是一个空对象,但由于其原型链,它似乎具有oldobj的所有值。
另一方面,如果您执行var newObj=new oldObj(),newobj的原型是oldobj.prototype,这是不必要的难以理解。
诀窍是使用
1 2 3 4 5 6
| Object.create=function(proto){
var F = function(){};
F.prototype = proto;
var instance = new F();
return instance;
}; |
它在这个函数中,只有在这里才应该使用new。之后,只需使用object.create()方法。该方法解决了原型问题。
- 老实说,我对这项技术并不热衷——它不会增加任何新的东西,而且正如你的答案所示,它甚至可能最终成为一根拐杖。imho,理解原型链和对象实例化对于理解javascript是至关重要的…但是如果直接使用它们会让你不舒服,那么使用一个助手函数来处理一些细节是很好的,只要你记得你在做什么。fwiw:这是ecmascript第5版标准的一部分,在某些浏览器中已经有了,所以你应该小心不要盲目地重新定义它!
- 顺便说一句:我不知道你为什么要做这个cw,但是如果你想用我所做的格式更正重新发布它,要小心避免这个复选框…
- 不必要的难以理解?var c = new Car()与var c = Object.create(Car.prototype); Car.call(c)相同。