JavaScript: The Good Parts - 如何完全不使用`new`

Posted

技术标签:

【中文标题】JavaScript: The Good Parts - 如何完全不使用`new`【英文标题】:JavaScript: The Good Parts - How to not use `new` at all 【发布时间】:2011-07-10 14:31:52 【问题描述】:

Crockford 的书 javascript: The Good Parts 说(第 114 页)构造函数应该总是以首字母大写(即 Point)命名,并且具有首字母大写字母的函数名称应与构造函数一起使用(其他所有内容都应为小写)。

此约定有助于我们避免忘记将new 运算符与构造函数一起使用。

他接着说“[a]n 更好的应对策略是根本不使用new。”

我的问题是,我们如何在不使用 new 的情况下编写 JavaScript?

我们可以使用文字[] 来避免new Object()new Array()。 我们可以避免new Number()new Boolean()new String()0true''。 我们可以用/pattern/ 之类的东西来避免new RegExp()

我们如何避免new Date()

而且,最重要的是,我们如何避免将new 与我们自己的自定义对象一起使用?

【问题讨论】:

原型设计,原型设计,原型设计。 他有什么论据?我有一个完整的项目,很大程度上依赖于new,它对组织它有很大帮助。 看看Can I construct a JavaScript object without using the new keyword 我这辈子都不明白你为什么要放弃这样的结构,似乎是出于自己的懒惰或为了弥补自己的健忘。尽管如此,还是很有趣。 @GrantThomas,IMO,它是为了弥补编程语言的“愚蠢”,在这种语言中可以省略new 这个词,直到运行时才发现。 【参考方案1】:

Crockford 提供了一个对象创建函数的示例,JS 本身应该在他的 Javascript 演讲中提供了一个示例,该演讲可在 http://developer.yahoo.com/yui/theater/ 上获得

然而,YUI(3) 团队本身使用“new”,并且他们确实遵循了他的建议(因为他是 Yahoo 首席 JS 架构师(更新:他继续前进,但在最初撰写此回复时声明是正确的) .我理解这个特定的陈述更多的是在“学术”层面上,应该是什么语言被设计成“正确的”而不是一些基于类的继承东西的残余物。他(恕我直言)说的那样事实证明 JS 是有冲突的,基于原型的,但有一个来自“经典类”继承语言的东西。

不过,JS 就是这样,去用“new”吧。

你可以在这里找到他的对象创建函数:http://javascript.crockford.com/prototypal.html

 if (typeof Object.create !== 'function') 
     Object.create = function (o) 
         function F() 
         F.prototype = o;
         return new F();
     ;
 
 newObject = Object.create(oldObject);

编辑:更新为使用 Crockford 的该功能的最新版本 - 共有三个。

更新 2015 年 6 月:我们使用 Object.create(...) 已经有一段时间了,所有当前浏览器都支持(包括 IE 9 及更高版本),因此无需使用 Crockford 的功能。

然而,事实证明,如果你使用Object.create,你应该确保你不要经常这样做:该功能比使用new Constructor()慢得多!

请参阅http://mrale.ph/blog/2014/07/30/constructor-vs-objectcreate.html 了解解释(V8 引擎),请参阅http://jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor/62 了解性能演示。

另一个不拒绝 new Constructor(...) 的原因是 ES6 classes 肯定会得到广泛采用,即使只是因为大多数 Javascript 开发人员来自基于类的语言这一简单原因。

还可以查看这篇文章,它主张 Object.create: http://davidwalsh.name/javascript-objects-deconstruction

不管你喜不喜欢,尤其是在你想与广泛的人分享的项目中(在空间和时间上——意思是正确的,也不是随着时间的推移,其他人接替你)有更多使用 @987654334 的理由@。

更新 2015 年 9 月:对于我自己,我已经开始使用 ES 2015 Javascript 来处理所有事情 - 使用 io.js 和/或 Babel。除了像 new Error(...) 这样的 Javascript 内置插件外,我也不会在我的项目中使用 any new。我更喜欢使用功能更强大的方法,我完全忽略了对象系统。 [my-object].prototypethis 完全从我的项目中消失了。很长一段时间以来,我都对这些想法持怀疑态度,“因为对象工作得很好”。但是在一个新的(io.js)项目开始时非常不情愿地尝试它之后,它“点击”了,我不明白为什么我浪费了二十年。好吧,不完全是,今天的 JS 引擎和硬件更有利于这种风格。特别是在 ES 2015 中,我建议提供一个完全没有任何 thisclass(新的 ES 2015 关键字或整个概念,基于使用 constructorFn.prototype)的函数式样式。这可能需要你几个星期,但一旦它“点击”我保证你永远不会回去 - 不是自愿的。它更方便、更强大。

更新 2018 年 2 月:虽然我仍然在做我在上一次更新中写的内容,但我现在想补充一点,有时课程很好。没有绝对的。 :-)

【讨论】:

您指的这里是否有特定的“功能风格”?或者只是一般地将函数式编程理念应用于 Javascript 以消除其中一些问题? @Mörre Noseshine 关于您的更新(2015 年 9 月),我真的很想看看您是如何实现这一目标的(不使用任何“新”或“这个”)。你能提供和例子吗?您是否使用工厂函数以及 Object.create 来执行此操作?谢谢。 @Magrangs 不,我只是调用函数。您存储在对象中的状态我存储在函数变量中 - 使用语言的(词汇)范围规则。如果外部需要访问我的内部状态,我会返回一个带有(仅)方法的对象(在我的词法范围内,因此可以访问),只是一个对象文字容器。它是必需的,因为一个函数只能有一个返回值。词法作用域代替了对象。 请不要破坏您的帖子。 我不会称之为破坏行为,而是启蒙【参考方案2】:

你被困在使用“新”来实例化其他人的对象。但是对于您自己的代码,您可以避免“this”和“new”的陷阱。

(顺便说一下,问题不在于 'new' 本身。但是用 'new' 实例化的对象可能在内部使用 'this'。使用 'this' 会导致频繁和微妙的错误,因为javascript 的 'this' 要求 调用者 做额外的工作来将被调用的方法绑定到正确的对象,并且在运行前很难 lint 或以其他方式检测到不正确的绑定。)

短版:

为避免使用“new”来实例化您编写的对象,只需从任何函数返回一个对象。在该函数内部,将任何方法附加到该对象并进行任何初始化。你完成了——这个函数既是你的类定义又是构造函数。

长版,例如:

以下“self”模式避免同时使用“new”和“this”。虽然该模式确实在每个对象中存储方法副本,但这并不重要,除非您在运行时创建大量对象。如果是这种情况,那么您始终可以使用http://justjs.com/posts/this-considered-harmful 中的“flyweight”模式。 (虽然该页面上的示例仍然使用了一点“this”,但也需要稍作调整以使其适应以下模式。)

// this function defines a "class" -- the whole function is the constructor
function Foo(x) 
    // create/init whatever object type you want here
    var self = x: x;
    // if subclassing, for instance, you can do:
    // var self = Baz(x);

    // public method
    self.foo = function() 
        return self.x;
    ;

    // public method
    self.bar = function() 
        console.log(self.x);
        logger();
    ;

    // private method
    function logger() 
        console.log(self.x);
    

    // ...more constructor bits can go here

    // don't forget to return self
    return self;


var f = Foo(1); 
var g = Foo(2); 
setTimeout(f.bar, 1000);
setTimeout(g.bar, 1000);

console.log(g.foo()); // 2
g.x = 5;
console.log(f.foo()); // 1
console.log(g.foo()); // 5

// ...then, 1 second later:
// 1  (from f.bar)
// 1  (from f.logger)
// 5  (from g.bar)
// 5  (from g.logger)

// blows up if uncommented
// f.logger();

【讨论】:

【参考方案3】:

不使用 new 并盲目关注 Crockford 是愚蠢的。

了解 JavaScript 并编写好的代码。使用 new 关键字是 JavaScript OO 的基石

避免new,你会错过很多好的 JavaScript 代码。

与其随意地从你的工具包中删减大量内容,不如学习并正确使用它。

Crockford 习惯说 JavaScript 中任何给他的代码带来错误的东西都是不好的。

我个人会继续说“[a]更好的应对策略是胜任。”

【讨论】:

我不会说new 是 JavaScript OO 的基石。 @Raynos:我不敢苟同;而new Object() 具有相同的结果(一个新的空对象),它们正是因为 不使用new 关键字。如果你有 es5 的 Object.create(),那么你唯一需要 new 的就是 DateError(在核心 JS 中。你也需要它用于浏览器类型,但很少。)你可以编写大量的、组织良好的javascript 不使用new. @Raynos:当然,绝对。对 javascript 中的new 的担忧在于缺乏判断函数是否需要new 的能力,以及如果您忘记new,在全局对象上运行构造函数的危险。可怜的 new 被指责为 this 在全局函数上的损坏。 呃...你拼错了“competent”:) @SeanMcMillan 所以两个月后我同意,new 是可怕的,使用Object.create :)【参考方案4】:

我也不知道如何避免new Date()new XMLHttpRequest()。但我确实知道如何避免将 new 用于我自己的类型。

首先,我从Object.create() 开始。这是一种 ES5 方法,因此并非在任何地方都可用。我使用es5-shim 添加它,然后我就可以开始了。

我喜欢模块模式,所以我首先将我的类型包装在一个自动执行的匿名函数 var Xyz = (function() ...)() 中。这意味着我有一个私人空间可以工作,而不会在全局命名空间中弄得一团糟。我返回一个带有create() 函数和prototype 属性的对象。 create() 功能适用于我这种类型的用户。当他们想要一个时,他们调用Xyz.create(),并取回一个新的、已初始化的我类型的对象。如果人们想要继承,prototype 属性可用。

这是一个例子:

var Vehicle = (function()
        var exports = ;
        exports.prototype = ;
        exports.prototype.init = function() 
                this.mph = 5;
        ;
        exports.prototype.go = function() 
                console.log("Going " + this.mph.toString() + " mph.");
        ;

        exports.create = function() 
                var ret = Object.create(exports.prototype);
                ret.init();
                return ret;
        ;

        return exports;
)();

继承看起来像这样:

var Car = (function () 
        var exports = ;
        exports.prototype = Object.create(Vehicle.prototype);
        exports.prototype.init = function() 
                Vehicle.prototype.init.apply(this, arguments);
                this.wheels = 4;
        ;

        exports.create = function() 
                var ret = Object.create(exports.prototype);
                ret.init();
                return ret;
        ;

        return exports; 

)();

【讨论】:

【参考方案5】:

您可以通过返回匿名对象并在构造函数中使用闭包来避免“新建”。这也有助于您隐藏私人数据。

考虑:

function SomeCounter(start) 

    var counter = start;

    return 
        getCounter : function() 
            return counter;
        ,

        increaseCounter : function() 
            counter++;
        

    ;

现在要使用它,你需要做的就是

var myCounter = SomeCounter(5);
myCounter.increaseCounter();
console.log(myCounter.getCounter()); //should log 6

这样做的好处是您不需要记住使用“新”,但如果您这样做不会伤害您。

var myCounter = new SomeCounter(5); //still works

【讨论】:

虽然这 是真的,但如果您使用 new 调用不需要它的函数,我会非常沮丧。并且将你所有的方法都变成闭包意味着你需要在你的类型的每个实例上存储每个方法。【参考方案6】:

这个问题已经被问及回答了:Is JavaScript's "new" keyword considered harmful?

正如 Raynos 所说,盲目追随 Crockford(或其他任何人)而不理解为什么他们会说他们所做的事情,这是愚蠢的。

【讨论】:

非常好的一点,因为在这种情况下,Crockford 谈到了 JS 的历史,以及它从何而来以及它应该如何发展的更大背景。由于我们最终使用的是 JS,因此我们使用“new”。【参考方案7】:

可以通过创建工厂函数来避免new

var today = Date.getToday();

(如果您想知道,您无法在工厂函数本身上避免它:)

Date.getToday = function()  return new Date(); ;

虽然我认为你应该创建这样的函数,如果它增加了语义值(如上面的例子)或者你可以默认一些构造函数参数。换句话说,不要只是为了避免使用new

【讨论】:

我认为他的意思是有人会这样做:Date.prototype.getToday = function() ... 虽然这是真的,但这不是道格拉斯·克罗克福德的意思,这个问题就是这样。见javascript.crockford.com/prototypal.html @Pointy:不,他的意思是他写的。关键是能够编写 Date.getToday() 而不是 new Date()。如果他在原型上声明函数,他将不得不编写 new Date().getToday(),这样就失去了练习的意义。 哦,好的,我知道你们现在在做什么。感谢您的澄清(并不是说最初不清楚;我只是感到困惑)。 特别为自己的类型提供工厂。即使你必须使用new,也不要让你的客户使用它。【参考方案8】:
function F()  return  /* your fields and methods here */  

【讨论】:

【参考方案9】:

我认为他关于不使用 new 的建议是概念性的(学术性的),不能从字面上理解。 Date 类是该规则的一个完美例外,因为您如何使用标准 ECMAScript 获取当前(或任意)日期对象?

但是,关于不将new 与您自己的自定义对象一起使用,您可以使用一些策略。一种是使用类似工厂的方法而不是构造函数,构造函数可以将对象实例作为参数来“祝福”您的新类型,或者默认使用新的对象字面量。考虑以下几点:

var newCar = function(o) 
  o = o || ;
  // Add methods and properties to "o"...
  return o;

【讨论】:

以上是关于JavaScript: The Good Parts - 如何完全不使用`new`的主要内容,如果未能解决你的问题,请参考以下文章

on-job time如何回答?

作文范文《Good Communication Is the Best Policy》

Dolphin BlockchainBlockchain is good for the luxury market

Technology, globalisation and the squeeze on good jobs

Go Pro八折特惠 @The Good Guys eBay

C - The Number Of Good Substrings CodeForces - 1217C