JavaScript的“新”关键字是否被视为有害(第2部分)?

时间:2011-06-16 15:54:13

标签: javascript

通过以下question阅读,我觉得大多数答案都忽略了为什么有些人(Crockford)选择不使用“new”关键字。这不是为了防止在没有“new”关键字的情况下意外调用函数。

根据Crockford关于原型继承的以下article,他实现了一种对象创建技术,该技术更清楚地展示了JS的原型性质。这项技术现在甚至在JS 1.8.5中实现。

他反对使用新的论点可以更清楚地概括为:

“这种间接性旨在使语言对经过专业训练的程序员来说更加熟悉,但却没有做到这一点,正如我们从Java程序员对JavaScript的非常低级的看法中看到的那样.JavaScript的构造函数模式没有吸引力它也模糊了JavaScript的真正原型性质。因此,很少有程序员知道如何有效地使用该语言。“

我不一定认为“新”有害,但我确实认为它确实“掩盖了JavaScript的真正原型性质”,因此在这一点上我必须同意Crockford。

对于使用“更清晰”的原型对象创建技术,您对使用“new”关键字有什么看法?

3 个答案:

答案 0 :(得分:13)

你是对的,使用new被认为是有害的,因为它没有足够强调JavaScript在原型中的OO。主要问题是行为太像经典类,而一个不应该考虑class。人们应该考虑对象并使用现有对象创建新对象作为蓝图。

new是JavaScript接受类似Java语法以获得“受欢迎程度”的日子的残余。

这些天我们使用Object.create进行原型OO并使用ES5 shim

不再需要new

在ES5普遍实施之前(只有FF3.6和IE8松弛)我们使用new,因为我们别无选择。 someFunction.prototype是进行原型继承的方法。

我最近写了"nice" demonstration of Object.create,但我仍然需要解决一些问题。重要的是将对象与工厂函数分开。

答案 1 :(得分:10)

我没有发现new模糊了我对该语言的原型性质。我已经花了几年时间才能很好地掌握这门语言(最初的错误就是潜入并开始编写代码而没有线索语言实际上是如何工作的,这是我的初始成本)。 / p>

我发现new表达的方式是在函数名称前加“new”或使用辅助函数等,不是:

var fido      = new Dog();          // Simple, clear
var rover     = Dog();              // Very unclear (fortunately people mostly don't do this, but I've seen it)
var scruffles = newDog();           // Clearer, but hacky
var fifi      = Object.create(Dog); // (Crockford) Verbose, awkward, not esp. clear

无论是原型还是基于类(并且大多数都与new关键字完全无关),我仍然认为最好将功能组合在一起构建块(对象或类或其他) )然后我可以在不影响这些构建块的情况下进行特定对象。对我而言,new作为一种清楚地表明我的意图的手段既不是优雅的,也不是典型的,只是很清楚。

对我而言,new与原型本身一样,是JavaScript的重要组成部分,因为奇妙的灵巧功能。这是没有冲突的。

说实话,有一个很多更多的程序员曾经使用new来创建新的事物而不是,尽管Crockford's,它仍然是JavaScript社区中的一种普遍做法努力(不要误解,我对Crockford非常尊重)。如果我为一个项目配备人员,我不希望再培训麻烦。

这并不是说你在JavaScript中定义原型对象的层次结构的方式永远是美丽和快乐的事情。这是一种皇家的痛苦,尤其是没有ECMAScript5增强功能。但是定义一个辅助函数来帮助你连接你的层次结构(无论你想叫它们),你就完成了。 (见下面的更新。)

[是的,关于构造函数被调用而没有new的整个事情真的是一个红色的鲱鱼(你做了说你不认为这也是一个要点)。你几乎从未在现实世界中看到它。实际上,JavaScript的一些功能非常好(例如StringNumber的方式);其他部分(Date ** shudder ** )并不是那么好......]


从ES2015(ES6)开始,由于新的类语法,创建原型和构造函数的层次结构变得轻而易举。不再需要助手了。

class Base {
    constructor(name) {
        this.name = name;
    }
    greeting() {
        return "Hi, I'm " + this.name;
    }
}

class Derived extends Base {
    constructor(name, age) {
        super(name);
        this.age = age;
    }
    greeting() {
        return super.greeting() + " and I'm " + this.age + " years old";
    }
}

这并不意味着我们当然希望他们拥有一切。当我需要扩展单个对象时,我使用Object.create效果很好。

答案 2 :(得分:2)

我对new的最大问题是它违反了开放/封闭原则。由于new操纵this的值的方式,构造函数关闭以进行扩展,这意味着如果需要扩展它,则必须修改它,可能会破坏进程中的调用者。

new不允许扩展工厂的一些示例:

  • 隐藏对象创建的详细信息。 (其余的这些是你可能想要这样做的例子)

  • 在工厂对象上存储可变原型和初始化函数,可通过this访问。 (使用new时,this始终引用新创建的对象。

  • 通过允许您向工厂对象添加功能(可扩展多态性)来扩展可能的对象类型池。

  • 使用this.call()(扩展代码重用)在实例化期间重新定义.apply()的含义。

  • 将代理返回到另一个内存空间(iframe,窗口,不同的计算机)中的新对象。

  • 有条件地返回对现有对象的引用(实际上,您可以使用new和构造函数执行此操作,但是this在构造函数中没有意义并且误导,因为新实例已分配如果你返回一个新对象以外的东西,则扔掉。)

  • 在不破坏呼叫者的情况下启用对实例化策略的更改。

注意:我一直很恼火,我不能轻易地使用Backbone.js中的任何一种策略,因为它会强制你使用new,除非你包裹它,但是你关闭其标准继承机制。相比之下,我从未发现自己很恼火,jQuery使用工厂函数来实例化jQuery包装的DOM集合。