JavaScript:好的部分 - 如何完全不使用 `new`
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5224295/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript: The Good Parts - How to not use `new` at all
提问by Rudiger
Crockford's book, JavaScript: The Good Parts, says (on page 114) that constructor functions should alwaysbe given names with an initial capital letter (ie. Point), and that function names with initial capital letters should onlybe used with constructor functions (everything else should be lowerCase).
Crockford 的书JavaScript: The Good Parts说(第 114 页)构造函数的名称应该始终以首字母大写(即 Point)命名,并且首字母大写的函数名称只能与构造函数一起使用(其他一切都应该是小写)。
This convention helps us avoid forgetting to use the new
operator with constructor functions.
这个约定帮助我们避免忘记在new
构造函数中使用运算符。
He goes on to say that "[a]n even better coping strategy is to not use new
at all."
他接着说“[一个]更好的应对策略是根本不使用new
。”
My question is, how do we program JavaScript without using new
at all?
我的问题是,我们如何在不使用 JavaScript 的情况下编写 JavaScript new
?
- We can avoid
new Object()
andnew Array()
with the literal{}
and[]
. - We can avoid
new Number()
,new Boolean()
, andnew String()
with0
,true
and''
. - We can avoid
new RegExp()
with something like/pattern/
.
- 我们可以避免使用
new Object()
和new Array()
文字{}
和[]
。 - 我们可以避免
new Number()
,new Boolean()
, andnew String()
with0
,true
and''
。 - 我们可以避免
new RegExp()
类似/pattern/
.
How do we avoid new Date()
?
我们如何避免new Date()
?
And, most importantly, how do we avoid using new
with our own custom Objects?
而且,最重要的是,我们如何避免使用new
我们自己的自定义对象?
回答by M?rre
Crockford gives an example for an object creation function as should have been provided by JS itself in one of his Javascript talks available on http://developer.yahoo.com/yui/theater/
Crockford 给出了一个对象创建函数的例子,它应该由 JS 本身在http://developer.yahoo.com/yui/theater/上的一个 Javascript 演讲中提供
However, the YUI(3) team itself uses "new", and they DO follow his recommendations (since he's the Yahoo chief JS architect (UPDATE: he moved on, but the statement was true when this response was originally written). I understand this particular statement to be more on an "academic" level, what SHOULD have been HAD the language been designed "right" and not with some leftovers of the class-based inheritance stuff. He (IMHO rightly) says that the way it turned out JS is conflicted, prototype based but with this one thing from "classical class" inheritance languages.
然而,YUI(3) 团队本身使用“new”,他们确实遵循他的建议(因为他是雅虎首席 JS 架构师(更新:他继续前进,但最初撰写此回复时该声明是正确的)。我理解这个特殊的声明更多是在“学术”层面上,应该是语言被设计“正确”而不是基于类的继承的一些剩余物。他(恕我直言正确)说结果是这样的JS 是冲突的,基于原型的,但是来自“经典类”继承语言的这一点。
However, JS is as it is so go and use "new".
然而,JS 就是这样去使用“new”。
You can find his object creation function here: http://javascript.crockford.com/prototypal.html
你可以在这里找到他的对象创建功能: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);
EDIT: Updated to use Crockford's latest version of that function - there are three.
编辑:更新为使用 Crockford 的该功能的最新版本 - 有三个。
UPDATEJune 2015: We have had Object.create(...)
for quite a while now, which all current browsers support (incl. IE 9 and above), so there was no need to use Crockford's function.
2015 年 6 月更新:我们已经有Object.create(...)
一段时间了,所有当前浏览器都支持(包括 IE 9 及更高版本),因此无需使用 Crockford 的功能。
However, it turns out that if you use Object.create
you should make sure that you don't do that a lot: That function is FAR slower than using new Constructor()
!
但是,事实证明,如果您使用Object.create
,则应确保不要经常这样做:该函数比使用 慢得多new Constructor()
!
See http://mrale.ph/blog/2014/07/30/constructor-vs-objectcreate.htmlfor an explanation (for the V8 engine), and see http://jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor/62for a performance demo.
有关说明(对于 V8 引擎),请参阅http://mrale.ph/blog/2014/07/30/constructor-vs-objectcreate.html,并参阅http://jsperf.com/object-create-vs- crockford-vs-jorge-vs-constructor/62用于性能演示。
Another reason to not turn your back on new Constructor(...)
is that ES6 classeswill surely see wide-ranging adoption even if only for the simple reason that most Javascript developers come from class-based languages.
另一个不反对的原因new Constructor(...)
是ES6 类肯定会被广泛采用,即使只是因为大多数 Javascript 开发人员来自基于类的语言的简单原因。
Also check out this article, which argues forObject.create
: http://davidwalsh.name/javascript-objects-deconstruction
另外,请查阅这篇文章,其中指出的Object.create
:http://davidwalsh.name/javascript-objects-deconstruction
Like it or not, especially in projects you want to share with a wide range of people (in space and time -- meaning right nor or over time, other people taking over from you) there are more reasons for using new
.
不管你喜不喜欢,特别是在你想与广泛的人分享的项目中(在空间和时间上——意味着正确或随着时间的推移,其他人接替你)有更多的理由使用new
.
UPDATESeptember 2015: For myself, I have begun to use ES 2015 Javascript for everything - using either io.js and/or Babel. I also don't use anynew
in my projects except for the Javascript built-ins like new Error(...)
. I prefer to use the far more powerful functional approach, I completely ignore the object system. [my-object].prototype
and this
are completely gone from my projects. For the longest time I was VERY skeptical of these ideas "because objects work just fine". But after very reluctantly giving it a try at the beginning of a new (io.js) project it "clicked" and I don't understand why I wasted two decades. Okay, not quite, today the JS engines and hardware are much more conducive to that style. Especially with ES 2015, I recommend giving a functional style entirely free of any this
and class
(the new ES 2015 keyword or the entire concept, based on using constructorFn.prototype
) a try. It may take you a few weeks but once it "clicks" I promise you won't ever go back - not voluntarily. It's so much more convenient and more powerful.
2015 年 9 月更新:就我自己而言,我已经开始将 ES 2015 Javascript 用于所有内容 - 使用 io.js 和/或 Babel。我还没有使用任何new
在我的项目除外的Javascript内建喜欢new Error(...)
。我更喜欢使用功能更强大的方法,我完全忽略了对象系统。[my-object].prototype
并且this
完全从我的项目中消失了。在很长一段时间里,我对这些想法非常怀疑,“因为对象工作得很好”。但是在一个新(io.js)项目开始时非常不情愿地尝试之后,它“点击”了,我不明白为什么我浪费了二十年。好吧,不完全是,今天 JS 引擎和硬件更有利于这种风格。特别是在 ES 2015 中,this
和class
(新的 ES 2015 关键字或整个概念,基于 using constructorFn.prototype
)尝试。这可能需要你几个星期,但一旦它“点击”我保证你永远不会回去 - 不是自愿的。它更方便,更强大。
UPDATEFebruary 2018: While I still do what I wrote in the previous update I now want to add that sometimes classes are fine. There are no absolutes. :-)
2018 年 2 月更新:虽然我仍在做我在上一次更新中写的内容,但我现在想补充一点,有时类很好。没有绝对的。:-)
回答by Sean McMillan
I don't know how to avoid new Date()
or new XMLHttpRequest()
either. But I do know how to avoid using new for my own types.
我不知道如何避免new Date()
或new XMLHttpRequest()
要么。但我知道如何避免为我自己的类型使用 new。
First, I start with Object.create()
. This is an ES5 method, so it's not available everywhere. I add it using the es5-shim, ad then I'm ready to go.
首先,我从Object.create()
. 这是一种 ES5 方法,因此并非随处可用。我使用es5-shim添加它,然后我准备好了。
I like the module pattern, so I start by wrapping my type in a self-executing anonymous function, var Xyz = (function() {...})()
. This means I have a private space to work without making a mess in the global namespace. I return an object with a create()
function, and a prototype
property. the create()
function is for users of my type. When they want one, they call Xyz.create()
, and get back a new, initialized object of my type. The prototype
property is available if people want to inherit.
我喜欢模块模式,所以我首先将我的类型包装在一个自动执行的匿名函数var Xyz = (function() {...})()
. 这意味着我有一个私人空间可以工作,而不会在全局命名空间中造成混乱。我返回一个带有create()
函数和prototype
属性的对象。该create()
功能适用于我这种类型的用户。当他们想要一个时,他们调用Xyz.create()
,并取回一个新的、初始化的我类型的对象。prototype
如果人们想继承,该财产是可用的。
Here's an example:
下面是一个例子:
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;
})();
and inheritance looks like this:
和继承看起来像这样:
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;
})();
回答by Raynos
Not using new
and blindly following Crockford is silly.
不使用new
和盲目跟随 Crockford 是愚蠢的。
Understand JavaScript and write good code. Using the new
keyword is the Cornerstoneof JavaScript OO.
了解 JavaScript 并编写好的代码。使用new
关键字是JavaScript OO的基石。
You are going to miss out on a lot of good JavaScript code by avoiding new
.
避免new
.
Rather than arbitrarily cutting huge chunks out of your toolkit, learn it and use it properly instead.
与其随意地从你的工具包中切出一大块,不如学习它并正确使用它。
Crockford has a habit of saying that anything in JavaScript which ever gave him a bug in his code is bad.
Crockford 有一个习惯,那就是 JavaScript 中任何给他的代码带来错误的东西都是糟糕的。
I would personally go on to say that "[a]n even better coping strategy is to be competent."
我个人会继续说“[一个]更好的应对策略是有能力。”
回答by Jord?o
You canavoid new
by creating factory functions:
您可以new
通过创建工厂函数来避免:
var today = Date.getToday();
(In case you were wondering, you can'tavoid it on the factory function itself:)
(如果你想知道,你不能在工厂函数本身上避免它:)
Date.getToday = function() { return new Date(); };
Although I only think you should create such functions if it adds semantic value (as in the case above) or if you can default some of the constructor parameters. In other words, don't do it just to avoidusing new
.
虽然我只认为你应该创建这样的函数,如果它增加了语义值(如上面的例子)或者如果你可以默认一些构造函数参数。换句话说,不要仅仅为了避免使用new
.
回答by Stephen
This question has already been asked and answered: Is JavaScript's "new" keyword considered harmful?
这个问题已经有人提出并回答了:JavaScript 的“new”关键字是否被认为有害?
As Raynos said, blindly following Crockford (or anyone else for that matter) without understanding whythey say the things they do, is silly.
正如雷诺斯所说,盲目追随克罗克福德(或其他任何人)而不理解他们为什么说他们所做的事情,是愚蠢的。
回答by maerics
I think his advice of not using new
at allis conceptual (academic) and not to be taken literally. The Date
class is a perfect exception to the rule because how else can you get a current (or arbitrary) date object using standard ECMAScript?
我觉得他没有使用的意见new
在所有的概念(学术),而不是从字面上理解。该Date
班是一个完美的例外,因为你怎么回事,可以得到使用标准的ECMAScript的电流(或任意)约会对象?
However, regarding not using new
with your own custom objects you can use a few strategies. One is to use factory-like methods instead of constructors which could take as an argument an object instance to "bless" into your new type, or use a new object literal by default. Consider the following:
但是,关于不使用new
您自己的自定义对象,您可以使用一些策略。一种是使用类似工厂的方法而不是构造函数,构造函数可以将对象实例作为参数“祝福”到您的新类型,或者默认情况下使用新的对象文字。考虑以下:
var newCar = function(o) {
o = o || {};
// Add methods and properties to "o"...
return o;
}
回答by Murali VP
function F() { return { /* your fields and methods here */ } }
回答by Zaven Nahapetyan
You can avoid "new" by returning an anonymous object and using a closure in your constructor. This also help you hide private data.
您可以通过返回匿名对象并在构造函数中使用闭包来避免“新建”。这也有助于您隐藏私人数据。
Consider:
考虑:
function SomeCounter(start) {
var counter = start;
return {
getCounter : function() {
return counter;
},
increaseCounter : function() {
counter++;
}
};
}
Now to use this, all you need to do is
现在要使用它,您需要做的就是
var myCounter = SomeCounter(5);
myCounter.increaseCounter();
console.log(myCounter.getCounter()); //should log 6
The beauty of this is that you do not need to remember to use "new", but if you do it won't hurt you.
这样做的好处是你不需要记住使用“new”,但如果你这样做了,它不会伤害你。
var myCounter = new SomeCounter(5); //still works
回答by stevegt
You're stuck with using 'new' to instantiate other people's objects. But for your own code, you can avoid the pitfalls of both 'this' and 'new'.
您一直坚持使用“new”来实例化其他人的对象。但是对于您自己的代码,您可以避免“this”和“new”的陷阱。
(By the way, the issue really isn't with 'new' itself. But an object being instantiated with 'new' is probably using 'this' internally. Use of 'this' leads to frequent and subtle bugs, because javascript's 'this' requires the callerto do extra work to bind the called method to the right object, and incorrect bindings are hard to lint or otherwise detect before runtime.)
(顺便说一句,问题真的不在于“新”本身。但是用“新”实例化的对象可能在内部使用“这个”。使用“这个”会导致频繁和微妙的错误,因为javascript的“这个” ' 要求调用者做额外的工作来将被调用的方法绑定到正确的对象,并且在运行之前很难检查或检测到错误的绑定。)
Short version:
精简版:
To avoid using 'new' to instantiate objects you write, just return an object from any function. Inside that function, attach any methods to that object and do any initialization. You're done -- that function is both your class definition and constructor.
为避免使用“new”来实例化您编写的对象,只需从任何函数返回一个对象。在该函数内,将任何方法附加到该对象并进行任何初始化。大功告成——该函数既是类定义又是构造函数。
Long version, with example:
长版本,例如:
The following 'self' pattern avoids use of both 'new' and 'this'. While the pattern does store method copies in each object, this won't matter unless you're creating a lot of objects at runtime. If that's the case, then you can always use the 'flyweight' pattern from http://justjs.com/posts/this-considered-harmful. (While the examples on that page still use 'this' a little, it's a slight tweak to adapt those to the following pattern as well.)
下面的“self”模式避免同时使用“new”和“this”。虽然该模式确实在每个对象中存储了方法副本,但除非您在运行时创建大量对象,否则这无关紧要。如果是这种情况,那么您始终可以使用http://justjs.com/posts/this-thinked-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();