日期:2014-05-16  浏览次数:20365 次

扩展JavaScript的正确方法(翻译)
本文翻译自【 Extending JavaScript – The Right Way 】

JavaScript comes with a lot of great functionality built in, but what if there is a function you need which is missing. How can we build them in seaminglessly in an elegant way that extends the functionality of our beloved JavaScript. The following will outline a couple methods to extend the existing functionality of JavaScript, both effective but one a little more functionally complete.

JavaScript 内建了很多很棒的函数,但也漏掉了一些我们很需要的,因此需要我们自己扩展。但如何才能将扩展的代码与亲爱的JavaScript优雅的融合在一起呢?接下来将向你展示几个小函数,扩展了已有的功能,让JavaScript更完整一点儿。

Say we want to create a function .capitalize() to extend the String type of JavaScript so that it behaves in a way similar to String.toLowerCase() or String.toUpperCase(). We can do this by prototyping the String object adding in our new function.

首先我们要为String类型扩展一个.capitalize()函数,它使用起来类似 String.toLowerCase() 或 String.toUpperCase() ,可以返回一个新的,被格式化为首字母大写,其他全部小写的字符串。我们可以用操作对象原型 prototype 的方式添加我们的新函数

This is usually done in the simplest way with the code below:

通常最简单的写法如下:

if(!String.prototype.capitalize)
{
    String.prototype.capitalize = function()
    {
        return this.slice(0,1).toUpperCase() + this.slice(1).toLowerCase();
    }
}


This works fine and dandy but lets say we were to do the following:

它能正常工作,但如果像下面这样用:

var strings = "yay";
for(i in strings) console.log(i + ":" + strings[i]);


We would get the output:

我们会得到下面的结果:

0: y
1: a
2: y
capitalize: function () { return this.slice(0, 1).toUpperCase() + this.slice(1).toLowerCase(); }


Our capitalize function shows up in our for loop, which is correct since it is now a property of all strings. The reason it is doing this is because the enumerable property for our new function is by default set to true.

我们的 capitalize 函数也出现在了循环中,并且作为一个属性出现在所有String对象中。造成此结果的原因是,我们新增加的函数,会被做上一个标记,它是通过设置改函数的 enumerable 属性为 true 来实现的,而通过这样的方式新增的函数默认就会将 enumerable 属性为 true 。

However, this was wreaking havoc on a plugin I had written that happened to be iterating through each character in a string. By simply changing the enumerable property to false we can avoid this problem which can be done by using the defineProperty method like so:

虽然在做String迭代操作时,我们书写的这个插件会造成严重的不良影响,但也不用如此担心。只要稍加修改,使用 defineProperty 函数来设置新增函数的 enumerable 值为 false,就可以解决这个问题,像下面这样:

if(!String.prototype.capitalize)
{
    Object.defineProperty(String.prototype, 'capitalize',
    {
       value: function()
       {
           return this.slice(0,1).toUpperCase() + this.slice(1).toLowerCase();
       },
       enumerable: false
    });
}


Now when we run our loop we get the outcome we were more likely expecting.

现在再运行之前的迭代代码,便会得到我们想要的结果:

var strings = "yay";
for(i in strings) console.log(i + ":" + strings[i]);

0: y
1: a
2: y


The reason for this may not seem as obvious when we’re looking at strings, but it gives us a lot of flexibility should we need it. It can come in really handy when defining our own objects and setting some default values that we would want to expose.

Below are just a few more examples you may wish to use in some of your own projects:

因为这个特性,字符串看上去并没有明显的变化,但却带来了很多我们需要的灵活性。借此,在实际应用中,我们可以方便的定义定义或设置我们自己的对象,使我们定义的方法可以按我们想要的方式展现给外界

下面是一些其他小函数的代