4

免责声明

  • 该线程应该为遇到类似问题的其他人提供帮助,并检查是否有更好的解决方案。我将附上我自己的解决方案,但欢迎提出想法和改进(除了使其更通用)。
  • 我知道一般来说,扩展内置对象是个坏主意。所以这个线程的一个假设是有一个很好的理由并且没有办法绕过它。

设想

作为开发人员,我想为someMethod所有 Javascript 对象添加一个方法,其中Object,NumberString.

我希望解决方案满足以下验收标准:

  • A)该解决方案在浏览器中工作
    • A1) 解决方案在严格模式下工作,以防脚本在严格上下文中使用
    • A2) 该解决方案在非严格模式下工作,因为'use strict';将在压缩过程中被删除,例如YUI 压缩器[1]
  • B)该解决方案适用于node.js
    • B1) 解决方案在严格模式下工作(原因见 A1)
    • B2) 解决方案在非严格模式下工作,原因与 B2 相同,加上 node.js 中的严格模式无法在功能级别激活[2]
  • C)我希望允许其他对象覆盖此方法
  • D)如果可能,我想控制该方法是否在for .. in循环中显示,以避免与其他库发生冲突
  • E) 解决方案应实际修改原型。

[1] Minfication 删除了严格指令
[2]有什么方法可以在节点中强制执行严格模式?

4

2 回答 2

2

我自己的解决方案

在试图解决这个问题时,我遇到了一些导致一个或另一个验收标准被打破的问题(例如 [1] 中描述的问题)。一段时间后,我想出了以下似乎对我有用的解决方案。当然,这可以用更通用的方式编写。

(function () {
    'use strict';

    var methodName = 'someMethod',
        /** Sample method implementations */
        __someMethod = {
            'object': function () {
                var _this = this.valueOf();

                return ['Object'].concat( Array.prototype.slice.call( arguments ) );
            },

            'number': function () {
                var _this = this.valueOf();

                return ['Number'].concat( Array.prototype.slice.call( arguments ) );
            },

            'string': function () {
                var _this = this.valueOf();

                return ['String'].concat( Array.prototype.slice.call( arguments ) );
            },

            'boolean': function () {
                var _this = this.valueOf();

                return ['Boolean', _this];
            }
        };

    if( Object.defineProperty ) {
        Object.defineProperty( Number.prototype, methodName, {
            value: __someMethod['number'],
            writable: true
        } );

        Object.defineProperty( String.prototype, methodName, {
            value: __someMethod['string'],
            writable: true
        } );

        Object.defineProperty( Boolean.prototype, methodName, {
            value: __someMethod['boolean'],
            writable: true
        } );

        Object.defineProperty( Object.prototype, methodName, {
            value: __someMethod['object'],
            writable: true
        } );
    } else {
        Number.prototype[methodName] = __someMethod['number'];
        String.prototype[methodName] = __someMethod['string'];
        Boolean.prototype[methodName] = __someMethod['boolean'];
        Object.prototype[methodName] = __someMethod['object'];
    }
})(); 

编辑:我更新了解决方案以添加 [1] 中提到的问题的解决方案。即它的行 (eg) var _this = this.valueOf();。如果使用,原因就很清楚了

'number': function (other) {
    return this === other;
}

在这种情况下,你会得到

var someNumber = 42;
console.log( someNumber.someMethod( 42 ) ); // false

当然,这不是我们想要的(同样,原因在 [1] 中说明)。所以你应该使用_this而不是this

'number': function (other) {
    var _this = this.valueOf();
    return _this === other;
}

// ...

var someNumber = 42;
console.log( someNumber.someMethod( 42 ) ); // true

[1]为什么`typeof this`返回“object”?

于 2013-08-22T20:28:22.770 回答
1

创建一个包装对象(注意这只是一个例子,它不是很健壮):

var $ = (function(){
  function $(obj){
    if(!(this instanceof $))
        return new $(obj);

    this.method = function(method){
        var objtype = typeof obj;
        var methodName = method + objtype[0].toUpperCase() + objtype.substr(1);
        typeof _$[methodName] == 'function' && _$[methodName].call(obj);
    }
  }

  var _$ = {};

  _$.formatNumber = function(){
    console.log('Formatting number: ' + this);
  }

  _$.formatString = function(){
    console.log('Formatting str: "' + this + '"');
  }

  _$.formatObject = function(){
    console.log('Formatting object: ');
    console.log(JSON.stringify(this));
  }

  return $;
})();

用法:

var num = 5;
var str = 'test';
var obj = {num: num, str: str};

var $num = $(num);
$num.method('format');

$(str).method('format');
$(obj).method('format');

演示

于 2013-08-22T20:53:56.897 回答