javascript - JavaScript" new" 关键字认为是有害的?

  显示原文与译文双语对照的内容

在另一个问题中,用户指出 new 关键字是危险的,并且提出了一个对象创建的解决方案,而不是使用 new 。 我不相信这是真的,主要是因为我使用了 Prototype,Scriptaculous和其他优秀的JavaScript库,每个都使用了 new 关键字。

在 js - 行动iii,尽管有这么多种,昨天我在锐剧院和他说的完全一样的东西,正在看,道格拉斯Crockford的谈话,他并没有使用他的程序中 new 关键字再也( 函数最终- 50: 23分钟 ) 。

它是否要使用'错误'new 关键字了? 使用它的优点和缺点是什么?

时间:

Crockford已经做了很多推广好的JavaScript技术。 他对语言关键元素的固执态度激发了许多有用的讨论。 也就是说,有太多的人将"错误"或者"有害的"声明为福音,拒绝超越人们的观点。 有时会有些 frustrating 。

从头构建每个对象相比,new 关键字提供的功能有几个优点:

  1. Prototype继承 。虽然经常被那些习惯于class-based面向对象语言的混淆和嘲笑,javascript继承技术是一种简单而令人惊讶的代码re-use方法。 新关键字是使用它的规范( 只有可用的cross-platform ) 方法。
  2. 性能。这是一个 side-effect 如果我想添加 10方法以及我所有的对象创建,我 只编写一个创建函数,可以手动为每个方法分配到每个新的对象- - 或者,我可以将它们分配给函数的创建 prototype,并使用 new 来标记新对象。 这不仅是更快的( Prototype上的每个方法都不需要任何代码),它避免了每个对象使用不同属性的膨胀。 在较慢的机器上,当创建许多对象时,这意味着大量的时间和内存。

是的,new 有一个重要的缺点,由其他答案巧妙地描述: 如果你忘记使用它,你的代码将在没有警告的情况下中断。 幸运的是,该缺点很容易缓解- 只需向函数本身添加一点代码:


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的优点,而不必担心意外误用的问题。 你甚至可以向检查添加一个断言,如果你的代码被破坏了。 或者,就像注释的那样,使用检查来引入运行时异常:


if (!(this instanceof arguments.callee) ) 
 throw new Error("Constructor called as a function");

( 注意,这个Fragment可以避免hard-coding的构造函数名,与前面的示例不同,它不需要实际实例化对象- 因此,它可以被复制到每个目标函数中,而无需修改。)

简单"类"约翰Resig将进入细节在该技术应用于实例化帖子,以及包括一个默认的建筑到你"类"这里行为方法。 绝对是值得一读的。。是他即将出版的图书是,秘密是非常有必要的忍者,它找出隐藏的黄金在这个和许多其他语言( 这个with 上会特别有启发作用的经验的人们一开始被这个much-maligned特征作为一种技巧)"有害的"特点是非常有必要的。

我刚刚阅读了他的Crockfords书籍"javascript: 好的部分"。我觉得他认为所有曾经咬过他的东西都是有害的:

关于 switch:

我从不允许 switch 案例落入下一个案例。 我曾经在我的代码中发现了一个 Bug,它是由于在做了一个有力的演讲之后立即通过了一个有力的演讲。 ( 第 97页,ISBN 978 -0-596-51774-8 )

关于++和- -

++ ( 增量) 和 -- ( 递减) 运算符通过鼓励 exessive trickiness来贡献坏代码。 它们仅次于启用病毒和其他安全威胁的错误架构。 ( 第 122页)

关于新建:

如果你忘记了包括新前缀,调用构造函数,函数,然后时此将不绑定到新的对象。 遗憾的是,这里 将被绑定到全局对象,因此不要通过扩充你的新的对象,并且你将会破坏全局变量。 这真的很糟糕。没有编译警告,而且没有运行时警告。 ( 第 49页)

还有更多,但我希望你能得到图片。

我对你的问题的回答: ,它不是有害的。 但是如果你忘了使用它,你会遇到一些问题。 如果你在一个良好的环境中开发,你会发现。

更新

在这个答案写了大约一年之后,5版本的ECMAScript被释放,支持严格模式 。 在严格模式下,this 不再绑定到全局对象,而是绑定到 undefined

Javascript是动态语言,有无数种方法可以让其他语言阻止你。

以防你可能会让你的鞋muddy,避免其中一个基本语言特性的基础上,如 new,你可能搞乱有点像拿你那崭新的鞋子,然后步行穿越雷区 just.

我使用的约定是函数名以小写字母开头,而实际上类定义以大写字母开头。 结果是一个非常引人注目的视觉线索,'语法'错误:-


var o = MyClass();//this is clearly wrong.

在这种良好的命名习惯之上。 在所有的功能都做完之后,它应该有一个动词,而类代表对象,而名词和形容词没有动词。


var o = chair()//Executing chair is daft.
var o = createChair()//makes sense.

有趣的是着色的语法有interpretted上面的代码。

我是Javascript新手,所以我可能没有太多的经验来提供一个不错的视角。 我想在这个"新建"上分享我的观点。

我来自 C# 世界,使用关键字"新建"很自然,它是工厂设计模式,看起来很奇怪。

当我第一次使用Javascript代码时,我没有意识到有"新建"关键字和类似于YUI模式的代码,它并不会让我很长时间陷入灾难。 在查看我编写的代码时,我忘记了某一行应该做什么。 更多的混乱是当我的代码是"dry-running"时,我的思想不能真正地在对象实例之间传输。

然后,我找到了"新建"关键字,它是"单独"。 使用新关键字,它创建了。 没有新关键字,我知道我不会混淆它,除非我正在调用的函数给我提供了强大的线索。

比如,对于 var bar=foo();,我没有什么线索,因为什么酒吧可能是。。 是返回值还是新创建的对象? 但是 var bar = new foo(); 我知道bar是一个对象。

我写了一篇关于如何不用新关键字来调用构造函数的问题。
它主要是教导,但它展示了如何创建使用或者不使用 new的构造函数,并不要求你添加样板代码来测试每个构造函数中的this

http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html

下面是技术的要点:


/**
 * 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() {}
}

下面是使用它的方法:


//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);

不使用new关键字的基本原理非常简单:

如果根本不使用它,你就会避免意外省略的陷阱。 YUI使用的构造模式,是一个如何避免新关键字的示例"


var foo = function () {
 var pub= { };
 return pub;
}
var bar = foo();

或者你可以这样做:


function foo() { }
var bar = new foo();

但如果这样做你运行的风险有人忘记在使用关键字,而这个 运算符被所有 fubar 。 因此,做这个( 除了你习惯于它) 没有优势。

在一天结束时: 是 defensive 。 你可以使用新语句? 是的。这会使你的代码更加危险? 是

如果你曾经写过 C++,就像在删除指针后将指针设置为空。

案例 1: new 不是必需的,应该避免


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

案例 2: new 是必需的,否则你将得到一个错误


new Date().getFullYear();//correct, returns the current year, i.e. 2010
Date().getFullYear();//invalid, returns an error

下面是对使用 new 运算符的两个最强参数的最简单的总结:

new 参数

  1. 设计为使用 new 运算符作为对象实例化的函数如果被错误地调用为正常函数,则会产生灾难性的后果。 这种情况下的函数代码将在调用函数的作用域中执行,而不是在本地对象的作用域中执行。 这可能导致全局变量和属性被灾难性后果覆盖。
  2. 于建筑和文体reasons,相关最后,写 function Func(),然后调用 Func.prototype 加开始为它,这样才可以调用 new Func() inheritance.以构建对象似乎着满是对某些开发人员来说,谁更愿意使用另一种风格的对象

有关这个参数的更多信息,请查看crockford伟大的和简明的图书 Javascript: 好的部分。事实上,还是看看吧。

赞成 new的参数

  1. 使用 new 操作符和Prototype赋值是快速的。
  2. 在全局命名空间中意外运行函数的构造函数代码时,如果你总是在构造函数函数中包含少量代码来检查它们是否正确调用,并在它们不是正确的情况下处理调用时,会很容易被阻止。

看到约翰博文的Resig 对于一个简单的关于该技术的特性以及用于在继承模型他主张的一个通用的更深层的解释。

...