JavaScript的“ new”关键字是否有害?[关闭]

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

尽管如此,昨天我还是在Douglas Crockford在YUI剧院观看了一次演讲,他说的一模一样,他new不再在代码中使用关键字(JavaScript上的Crockford-Act III:终极功能-50:23分钟)。

使用new关键字是否“不好” 使用它的优缺点是什么?

江山如画2020/03/12 14:16:36

我认为new是邪恶的,不是因为如果您忘记错误使用它可能会导致问题,而是因为它会破坏继承链,从而使该语言难以理解。

JavaScript是基于原型的面向对象。因此,每个对象都必须像这样从另一个对象创建var newObj=Object.create(oldObj)这里oldObj称为原型的newObj(因此“基于原型”)。这意味着,如果没有找到一个属性newObj那么它将在搜索oldObj因此,默认情况下,newObj将是一个空对象,但是由于其原型链,它似乎具有oldObj的所有值

在如果你做的另一方面var newObj=new oldObj(),原型newObjoldObj.prototype,这是不必要的难以理解。

诀窍是使用

Object.create=function(proto){
  var F = function(){};
  F.prototype = proto;
  var instance = new F();
  return instance;
};

在此函数内部,仅在此处应使用new。之后,只需使用Object.create()方法。该方法解决了原型问题。

JinJin老丝2020/03/12 14:16:36

我同意佩斯和这里的一些观点。

在我看来,“新”似乎是自我描述对象的创建,而Greg Dean所描述的YUI模式被完全遮盖了

有人可能写的可能性var bar = foo;或者var bar = baz();baz不是对象创建方法的可能性似乎危险得多

Tony达蒙Mandy2020/03/12 14:16:36

不使用new关键字的原理很简单:

通过完全不使用它,可以避免因意外遗漏而导致的陷阱。YUI使用的构造模式是如何完全避免使用新关键字的示例”

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

或者,您可以这样:

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

但是这样做会冒着有人忘记使用new关键字,而this运算符全是富巴的风险。AFAIK没有这样做的优势(除了您已经习惯了)。

在一天结束时:这是关于防御。 您可以使用新的陈述吗?是。它会使您的代码更危险吗?是。

如果您曾经写过C ++,则类似于删除指针后将其设置为NULL。

小胖凯樱2020/03/12 14:16:36

我认为“新”可增加代码的清晰度。清晰是值得的。很高兴知道有陷阱,但是通过避免清晰性来避免陷阱似乎对我而言并不可行。

LItachi2020/03/12 14:16:36

Javascript是一种动态语言,有数不胜数的方法可以弄乱另一种语言会阻止您的位置。

避免使用基本语言功能(例如new,可能会搞砸了)有点像在穿过雷区之前脱下闪亮的新鞋,以防万一您的鞋子浑浊。

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

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

除此以外,良好的命名习惯也有帮助。在所有函数完成工作之后,因此名称中应该有一个动词,而类表示对象,是不带动词的名词和形容词。

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

有趣的是,SO的语法着色如何解释了上面的代码。

小胖凯樱2020/03/12 14:16:36

另一种情况新就是我所说的维尼编码小熊维尼跟随他的肚子。我说去你正在使用,而不是语言反对它。

该语言的维护者很可能会针对他们尝试鼓励的惯用语优化该语言。如果他们在语言中添加了新关键字,他们可能会认为在创建新实例时明确一点是有意义的。

遵循该语言意图编写的代码将在每个发行版中提高效率。避免使用该语言的关键构造的代码将随着时间而受苦。

编辑:这远远超出了性能。我无法数出我听到(或说过)“他们为什么这么做?”的次数。当发现奇怪的代码时。经常发现,在编写代码时,有一些“好的”理由。遵循语言的道理是您最好的保证,因为从现在开始几年后都不会嘲笑您的代码。

神无伽罗2020/03/12 14:16:36

我写了一篇有关如何减轻在没有new关键字的情况下调用构造函数的问题的文章。
这主要是讲解性的,但是它显示了如何创建可以使用或不使用的构造函数,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);
Tony阿飞2020/03/12 14:16:36

我刚刚阅读了他在克罗克福德(Crockfords)的书“ Javascript:好的部分”中的部分内容。我感觉到他认为曾经刺伤他的一切都是有害的:

关于开关掉线:

我绝不允许切换案例陷入下一个案例。我曾在激烈的演讲中谈到为什么有时有用,然后立即由于意外的失败导致代码错误。(第97页,ISBN 978-0-596-51774-8)

关于++和-

众所周知,++(递增)和-(递减)运算符会通过鼓励复杂性而导致不良代码。在启用病毒和其他安全威胁方面,它们仅次于错误的体系结构。(第122页)

关于新:

如果你忘记了包含新的 调用构造函数时前缀,那么将不会被绑定到新的对象。遗憾的是, 将绑定到全局对象,因此您将无法破坏全局变量,而不是增加新对象。那真是太糟糕了。没有编译警告,也没有运行时警告。(第49页)

还有更多,但我希望您能明白。

我对您的问题的回答:不,这不是有害的。但是如果忘记了使用它的时间,可能会遇到一些问题。如果您在良好的环境中进行开发,则会注意到这一点。

更新资料

编写此答案大约一年后,发布了ECMAScript的第五版,并支持严格模式在严格模式下,this不再绑定到全局对象,而是绑定到undefined

Stafan卡卡西2020/03/12 14:16:36

Crockford在推广良好的JavaScript技术方面做了很多工作。他对语言关键要素的自以为是的态度引发了许多有用的讨论。就是说,太多的人把每一个“坏”或“有害”的宣告当作福音,拒绝超越一个人的视线。有时可能会令人沮丧。

new与从头开始构建每个对象相比,使用关键字提供的功能具有多个优点:

  1. 原型继承尽管基于类的OO语言的人们经常将怀疑和嘲笑混为一谈,但是JavaScript的本机继承技术是一种简单且令人惊讶的有效代码重用方法。并且new关键字是使用它的规范方法(并且只有可用的跨平台方法)。
  2. 性能。这是#1的副作用:如果我想向创建的每个对象添加10个方法,我可以编写一个创建函数,将每个方法手动分配给每个新对象...或者,我可以将它们分配给创建功能,prototype并用于new标记新对象。这样不仅速度更快(原型上的每个方法都不需要代码),而且还避免了为每个方法使用单独的属性来膨胀每个对象。在较慢的机器(尤其是较慢的JS解释器)上,当创建许多对象时,这可能意味着可以节省大量的时间和内存。

是的,它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");

(请注意,此代码段能够避免对构造函数名称进行硬编码,因为与前面的示例不同,它无需实际实例化对象-因此,可以将其复制到每个目标函数中,而无需进行修改。)

John Resig在他的“类”实例化简单文章中详细介绍了此技术,并包括一种默认情况下将此行为构建到“类”中的方法。绝对值得一读...正如他即将出版的书《 JavaScript忍者的秘密》一样,该书在JavaScript语言的此功能和许多其他“有害”功能中发现了隐藏的金子(该with那些最初被解雇的人特别有启发性此功能非常align头)。