在另一个问题中,一个用户指出使用new关键字是危险的,并提出了一个不使用new的对象创建解决方案。我不相信这是真的,主要是因为我使用过Prototype、Script.aculo.us和其他优秀的JavaScript库,它们都使用new关键字。
尽管如此,昨天我在YUI剧院看了Douglas Crockford的演讲,他说了完全相同的事情,他不再在他的代码中使用new关键字(Crockford谈JavaScript -第三幕:函数终极- 50:23分钟)。
使用new关键字“不好”吗?使用它的优点和缺点是什么?
不使用new关键字的理由很简单:
通过根本不使用它,您可以避免意外遗漏它的陷阱。YUI使用的构造模式是一个如何完全避免new关键字的例子:
var foo = function () {
var pub = { };
return pub;
}
var bar = foo();
或者,你可以这样做:
function foo() { }
var bar = new foo();
但是这样做有可能会有人忘记使用new关键字,并且this操作符完全是FUBAR。据我所知,这样做没有任何好处(除了你已经习惯了)。
在一天结束的时候:这是关于防御性的。你会用这个新语句吗?是的。这会让你的代码更危险吗?是的。
如果你曾经写过c++,这类似于在删除指针后将它们设置为NULL。
不使用new关键字的理由很简单:
通过根本不使用它,您可以避免意外遗漏它的陷阱。YUI使用的构造模式是一个如何完全避免new关键字的例子:
var foo = function () {
var pub = { };
return pub;
}
var bar = foo();
或者,你可以这样做:
function foo() { }
var bar = new foo();
但是这样做有可能会有人忘记使用new关键字,并且this操作符完全是FUBAR。据我所知,这样做没有任何好处(除了你已经习惯了)。
在一天结束的时候:这是关于防御性的。你会用这个新语句吗?是的。这会让你的代码更危险吗?是的。
如果你曾经写过c++,这类似于在删除指针后将它们设置为NULL。
JavaScript是一种动态语言,有无数种方法可以把其他语言阻止你的事情搞砸。
避免使用像new这样的基本语言特性,因为你可能会搞砸,这有点像在穿过雷区之前脱掉你闪闪发光的新鞋,以防你的鞋被弄脏。
我使用了一种约定,函数名以小写字母开头,而实际上是类定义的“函数”以大写字母开头。结果是一个非常引人注目的视觉线索,“语法”是错误的:
var o = MyClass(); // This is clearly wrong.
最重要的是,良好的命名习惯会有所帮助。毕竟,函数是做事情的,因此它的名字中应该有一个动词,而类代表对象,是没有任何动词的名词和形容词。
var o = chair() // Executing chair is daft.
var o = createChair() // Makes sense.
Stack Overflow的语法着色是如何解释上面的代码的,这很有趣。
我刚刚读了Crockford的书《JavaScript: The Good parts》的一部分。我有一种感觉,他认为凡是咬过他的东西都是有害的:
关于开关故障:
我从不允许开关箱掉下来
进入下一个案例。我曾经发现
我的代码中有一个bug,是由
无意中立刻落空
在做了一次有力的演讲之后
为什么有时候会失败
有用的。(第97页,ISBN
978-0-596-51774-8)
关于++和——:
++(递增)和——(递减)
运营商已经知道
通过鼓励来促成糟糕的代码
过度的诡计多端。他们是第二
只有错误的架构在
启用病毒和其他安全性
威胁。(第122页)
关于新:
如果你忘了说新的
调用构造函数时的前缀
函数,那么这个就不是
绑定到新对象。遗憾的是,这
将被绑定到全局对象,那么
不是扩大你的新对象,
你将在全球范围内大肆宣传
变量。这真的很糟糕。在那里
是否没有编译警告,并且没有
运行时警告。(49页)
还有更多,但我希望你能理解。
对于你的问题,我的回答是:不,它是无害的。但如果你忘记使用它时,你可能会有一些问题。如果你在一个良好的环境中发展,你会注意到这一点。
在ECMAScript的第5版中,支持严格模式。在严格模式下,this不再绑定到全局对象,而是绑定到undefined。
我认为new是邪恶的,不是因为如果你错误地忘记使用它,它可能会引起问题,而是因为它破坏了继承链,使语言更难理解。
JavaScript是基于原型的面向对象的。因此,每个对象都必须像这样从另一个对象创建:var newObj= object .create(oldObj)。这里oldObj被称为newObj的原型(因此是“基于原型的”)。这意味着如果一个属性在newObj中没有找到,那么它将在oldObj中被搜索。默认情况下,newObj将是一个空对象,但由于它的原型链,它似乎拥有oldObj的所有值。
另一方面,如果执行var newObj=new oldObj(),则newObj的原型是oldObj。原型,这是很难理解的。
诀窍在于使用
Object.create=function(proto){
var F = function(){};
F.prototype = proto;
var instance = new F();
return instance;
};
它在这个函数中,并且只有在这里才应该使用new。在此之后,只需使用Object.create()方法。该方法解决了原型问题。