JavaScript:好的部分 - 如何完全不使用 `new`

发布于 2024-10-20 14:53:08 字数 735 浏览 6 评论 0 原文

Crockford 的书《JavaScript:The Good Parts》(第 114 页)指出,构造函数的名称应始终以大写字母开头(即 Point),并且首字母大写的函数名称只能与构造函数一起使用(其他所有内容都应小写)。

这个约定帮助我们避免忘记在构造函数中使用 new 运算符。

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

我的问题是,我们如何在不使用 new 的情况下编写 JavaScript 代码?代码>新根本吗?

  • 我们可以使用文字 {}[] 来避免使用 new Object()new Array()
  • 我们可以使用 0、< 来避免 new Number()new Boolean()new String()代码>true 和''
  • 我们可以使用 /pattern/ 之类的东西来避免 new RegExp()

我们如何避免new Date()

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

Crockford's book, JavaScript: The Good Parts, says (on page 114) that constructor functions should always be given names with an initial capital letter (ie. Point), and that function names with initial capital letters should only be used with constructor functions (everything else should be lowerCase).

This convention helps us avoid forgetting to use the new operator with constructor functions.

He goes on to say that "[a]n even better coping strategy is to not use new at all."

My question is, how do we program JavaScript without using new at all?

  • We can avoid new Object() and new Array() with the literal {} and [].
  • We can avoid new Number(), new Boolean(), and new String() with 0, true and ''.
  • We can avoid new RegExp() with something like /pattern/.

How do we avoid new Date()?

And, most importantly, how do we avoid using new with our own custom Objects?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

愿与i 2024-10-27 14:53:08

Crockford 给出了一个对象创建函数的示例,该示例应该由 JS 本身在他的一次 Javascript 演讲中提供,该演讲位于 http://developer.yahoo.com/yui/theater/

然而,YUI(3) 团队本身使用“新”,并且他们确实遵循他的建议(因为他是雅虎首席 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,您应该确保不要经常这样做:该函数比使用 慢得多新的构造函数()!

请参阅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 类 肯定会得到广泛采用,即使只是因为大多数 Javascript 开发人员来自基于类的语言这一简单原因。

另请查看这篇文章,其中支持 Object.createhttp://davidwalsh.name/javascript-objects-deconstruction

不管你喜欢与否,尤其是在你想要与广泛的人分享的项目中(在空间和时间上——意思是正确或过度)时间,其他人接替你)使用 new 有更多理由。

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

更新 2018 年 2 月:虽然我仍然按照之前的更新中所写的内容进行操作,但现在我想补充一点,有时类是可以的。没有绝对的事情。 :-)

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/

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.

However, JS is as it is so go and use "new".

You can find his object creation function here: 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.

UPDATE June 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.

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()!

See http://mrale.ph/blog/2014/07/30/constructor-vs-objectcreate.html for an explanation (for the V8 engine), and see http://jsperf.com/object-create-vs-crockford-vs-jorge-vs-constructor/62 for a performance demo.

Another reason to not turn your back on new Constructor(...) is that ES6 classes will surely see wide-ranging adoption even if only for the simple reason that most Javascript developers come from class-based languages.

Also check out this article, which argues for 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.

UPDATE September 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 any new 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.

UPDATE February 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. :-)

甜点 2024-10-27 14:53:08

我也不知道如何避免 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; 

})();

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.

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.

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.

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; 

})();
懒猫 2024-10-27 14:53:08

不使用 new 并盲目追随 Crockford 是愚蠢的。

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

如果避免使用 new,您将会错过很多优秀的 JavaScript 代码。

不要随意从你的工具包中删除大量内容,而是学习它并正确使用它。

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

我个人会继续说“更好的应对策略就是有能力。”

Not using new and blindly following Crockford is silly.

Understand JavaScript and write good code. Using the new keyword is the Cornerstone of JavaScript OO.

You are going to miss out on a lot of good JavaScript code by avoiding 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.

I would personally go on to say that "[a]n even better coping strategy is to be competent."

南薇 2024-10-27 14:53:08

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

var today = Date.getToday();

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

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

尽管我认为只有在添加语义值(如上面的情况)或者可以默认某些构造函数参数时才应该创建这样的函数。换句话说,不要只是为了避免使用new而这样做。

You can avoid new by creating factory functions:

var today = Date.getToday();

(In case you were wondering, you can't avoid 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 avoid using new.

树深时见影 2024-10-27 14:53:08

这个问题已经被提出并回答: JavaScript 的“new”关键字被认为是有害的吗?

正如雷诺斯所说,盲目跟随克罗克福德(或其他任何人)而不理解他们为什么说他们所做的事情是愚蠢的。

This question has already been asked and answered: Is JavaScript's "new" keyword considered harmful?

As Raynos said, blindly following Crockford (or anyone else for that matter) without understanding why they say the things they do, is silly.

蒗幽 2024-10-27 14:53:08

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

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

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

I think his advice of not using new at all is 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?

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:

var newCar = function(o) {
  o = o || {};
  // Add methods and properties to "o"...
  return o;
}
阿楠 2024-10-27 14:53:08

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

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

。) 简短版本:

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

长版本,例如:

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

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'.

(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 caller to do extra work to bind the called method to the right object, and incorrect bindings are hard to lint or otherwise detect before runtime.)

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.

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.)

// 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();

抱猫软卧 2024-10-27 14:53:08
function F() { return { /* your fields and methods here */ } }
function F() { return { /* your fields and methods here */ } }
提赋 2024-10-27 14:53:08

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

考虑一下:

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

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

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

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.

var myCounter = new SomeCounter(5); //still works
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文