向Object/Number/String原型添加方法

Adding methods to Object / Number / String prototype

本文关键字:添加 方法 原型 Number Object String      更新时间:2023-09-26

免责声明

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

场景

作为一名开发人员,我想向所有Javascript对象添加一个方法someMethod,其中ObjectNumberString的实现不同。

我希望解决方案符合以下验收标准:

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

[1] Mineration删除了严格的指令
[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]中提到的问题添加了解决方案。也就是说,它是线路(例如)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"返回"对象";?

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

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');

演示