【问题标题】:How can I add a property to Object.prototype without it being applied to Number.prototype?如何在不将属性应用于 Number.prototype 的情况下将属性添加到 Object.prototype?
【发布时间】:2015-01-22 08:18:20
【问题描述】:

我的目标是创建一个 ma​​ster_script.js。主要用于开发的处理程序文件。

此文件的一个小节专门用于自定义基础对象的原型:

  1. 字符串
  2. 号码
  3. 数组
  4. 对象
  5. 日期
  6. 功能
  7. 布尔值

所以当我写出我的代码块时......

/********************************************************/
Object.defineProperty(
    Number.prototype,'len',
    {get:function(){
        str=this.toString()
        return str.length
    }}
)
/********************************************************/
n=123
o={123:'abc',abc:123}
/********************************************************/
console.log(
    'n              ⇒ ',n,
    '\n n.len       ⇒ ',n.len,
    '\n n.__proto__ ⇒ ',n.__proto__
)
/********************************************************/

工作正常!

  • 当我在 控制台 中展开 n.__proto__ 时,它会显示 len: (...) 属性和它的 getter 函数 get len: function (){
  • 当我在 控制台 中键入 n. 时,它在属性|方法列表中清晰可见。

当我为 o 变量配置相同的设置时,问题就开始了:

/********************************************************/
Object.defineProperty(
    Number.prototype,'len',
    {get:function(){
        str=this.toString()
        return str.length
    }}
)
/******************************/
Object.defineProperty(
    Object.prototype,'len',
    {get:function(){
        cnt=0
        for(i in this)  cnt++;
        return cnt
    }}
)
/********************************************************/
n=123
o={123:'abc',abc:123}
/********************************************************/
console.log(
    'n              ⇒ ',n,
    '\n n.len       ⇒ ',n.len,
    '\n n.__proto__ ⇒ ',n.__proto__
)
/******************************/
console.log(
    'o              ⇒ ',o,
    '\n o.len       ⇒ ',o.len,
    '\n o.__proto__ ⇒ ',o.__proto__
)
/********************************************************/

我注意到的第一件事是,当我现在在 控制台 中键入 n.o. 时,属性|方法的弹出列表不再包含对 len 属性的引用,但是如果我输入完整的扩展名n.leno.len 我会得到32 的预期结果...

所以我知道代码是合法的,但我需要 console 弹出窗口,因为 7 个基础对象中的每一个都有大约 40 种不同的属性和方法...

所以我写了一个测试块来尝试找出问题:

/********************************************************/
Object.defineProperty(
    Object.prototype,'dis',
    {get:function(){return this}}
)
/******************************/
Object.defineProperty(
    Number.prototype,'len',
    {get:function(){return this.length}}
)
/********************************************************/
o={123:'abc',abc:123}
n=123
e=document.createElement('option')
/********************************************************/
console.log(
    'o              ⇒ ',o,
    '\n o.__proto__ ⇒ ',o.__proto__
)
/******************************/
console.log(
    'n              ⇒ ',n,
    '\n n.__proto__ ⇒ ',n.__proto__
)
/******************************/
console.log(
    'e              ⇒ ',e,
    '\n e.__proto__ ⇒ ',e.__proto__
)
/********************************************************/

控制台 中为 on 和现在的 e 扩展 .__proto__ 之后,我注意到所有 3 个都被赋予了我最初拥有的 dis 属性试图仅分配给 o 对象。

然后我破解了:Number.prototype 本身就是一个对象,所以它从Object.prototype 继承了dis 属性

我如何才能将dis 属性仅附加到o 对象而不被nObject.prototype 继承?

【问题讨论】:

  • 哇。这是一个long 问题。我是否正确将其缩小到 如何将属性添加到 Object.prototype 而不将其应用于 Number.prototype
  • 所有内置构造函数原型都继承自 Object.prototype,因此添加到其中的属性出现在其他对象上也就不足为奇了。这就是长期以来修改 Object.prototype 被视为一个坏主意的原因。
  • 是的,对不起@RGraham,你是对的,我只是认为一些案例历史会帮助你理解我想要实现的目标,我试图避免我已经尝试过的简单解决方案,比如下面的第一个答案...
  • @RobG:我已经知道了!事情是我只是在学习为什么它是如此真实。

标签: javascript object prototype defineproperty


【解决方案1】:

该文件的一个小节专门用于自定义基础对象的原型

哎呀。恕我直言,这不是最好的主意。特别是修改Object 原型。是的。

所以我知道代码是合法的,但我需要控制台弹出窗口,因为 7 个基础对象中的每一个都有大约 40 种不同的属性和方法...

为什么?您是在浏览器控制台中进行开发吗?

你有没有告诉我如何将 dis 属性单独附加到 o 对象而不被 n 从 Object.prototype 继承?

好的...

Object.defineProperty(
    o, 'dis',
    { get:function(){ return this; } }
);

怎么样?

您添加到Object 原型的任何内容都会显示在几乎所有内容上(这就是为什么这是一个坏主意)。

由于o 继承自Object,因此无法定义仅显示在普通对象上而不显示在其他所有对象上的属性。您的选择是:

  • 直接在o上定义属性,或者
  • 不要为o 使用普通对象,而是从您自己的自定义类型创建o 并将您的属性放在该自定义类型的原型上(比修改内置类型的原型要好得多)。李>


注意:当然,您可以修改Number.prototype 以使dis 属性为undefined
Object.defineProperty(Number.prototype, 'dis', {
    value: void 0
});

console.log((9).dis);

就数字而言,这将解决您的问题,但 dis 属性仍将存在于几乎所有其他存在的东西上。

看在上帝的份上,请使用分号。想想孩子们。

【讨论】:

  • geesh @JLRishe,在你的公开声明中,你听起来就像是辛普森一家的教授。哈哈。我确实明白你所说的,但你提出的解决方案仍然打折能够在 js 中使用的任何对象上请求 {}.len 的可用性......原始 ms.js .len 代码是ms.len(obj)obj.len 看起来更整洁。欢迎任何其他解决方法!
  • ps。 为什么?您是在浏览器控制台中进行开发吗? 我不是,但我正在使用控制台更清楚地查看我正在添加的对象属性,只需在控制台中扩展对象而不是编写代码块来列出所有属性。
【解决方案2】:

看看这个:

/********************************************************
⇒   create the master objects.
/********************************************************/
function MasterObject(dis){
    Object.defineProperty(
        this,'this_object',
        {get:function(){return dis}}
    )
}
/******************************/
function MasterArray(dis){
    Object.defineProperty(
        this,'this_array',
        {get:function(){return dis}}
    )
}
/********************************************************
⇒   define the master properties.
/********************************************************/
Object.defineProperty(
    Object.prototype,'_',
    {get:function(){return new MasterObject(this)}}
)
/******************************/
Object.defineProperty(
    Array.prototype,'_',
    {get:function(){return new MasterArray(this)}}
)
/********************************************************
⇒   example to expand in the console.
/********************************************************/
x={a:1,b:2,c:3,d:4,e:5}
y=[]
    y['a']=1
    y['b']=2
    y['c']=3
    y['d']=4
    y['e']=5
z=[x,y]
/********************************************************
⇒   open the console, type [z], hit [enter] and expand...
/********************************************************/

纲要:

  • 假设我们在Object.prototype 上定义了一个名为len 的属性并将其值设置为5
  • 现在,如果我们调用 {}.len,我们会得到 5 的结果;如果我们调用 [].len"".len#.len 等,由于在实例化时从 Object.prototype 继承,我们会得到相同的结果。
  • 但是假设我们随后在 Array.prototype 上定义了一个具有相同名称的属性:- len 并将其值设置为 50
  • 现在如果我们调用{}.len 等,我们会得到相同的结果5,但如果我们调用[].len,我们会得到50,因为Array.prototype 是最近创建的,它的len 定义会覆盖@987654337 @ 的版本。

解决方案:

  • 因此,如果我们只为 Object.prototype 定义 1 个属性,为简单起见调用 _,并将其值设置为仅包含特定于 objects 的处理程序的子结构对象。
  • 那么如果我们对Array.prototype 执行相同的操作,但将此_ 属性的值设置为另一个仅包含特定于数组 的处理程序的子结构。
  • 然后,与上面列表中的 .len 属性一样,Array.prototype_ 版本会覆盖 Object.prototype 的版本,因此我们有 2 个完全独立的 _ 属性,没有其他继承。

缺点:

  • 不能再以简单的方式{}.len 访问属性,现在必须以{}._.len 为前缀。

好处:

  • Object.prototype 上定义属性时,整个任务可能会变成一场自相矛盾的噩梦,即使是向控制台抛出的错误也会继承这些属性,如果您向Object.prototype 添加了 100 个新属性|方法,那么当您在控制台中展开任何错误!
  • 此方法确保只有 1 个属性可见 _,并且该属性可自定义为所有者对象的类型。

扩展:

  • 我正在考虑修改此代码以适应不符合此标准的各种对象,例如:
x=document.getElementsByTagName('td')
y=x._.len

喜欢:

function MasterObject(dis){
    if(dis.constructor.name=='HTMLCollection'){
        Object.defineProperty(
            this,'len',
            {get:function(){
                cnt=0
                for(ia in dis) cnt++;
                return cnt
            }}
        )
    }
        else{
            Object.defineProperty(
                this,'this_object',
                {get:function(){return dis}}
            )
        }
}

所以x._.len 可用于任何对象列表,但不能说{a:1},因为它的constructor.nameobject 而不是HTMLCollection

这是一个宠物项目。它只是在它自己的原型阶段,我正在寻找关于如何扩展这个概念的想法,从那些有经验的人那里,然后我要么回到旧的方式,要么打破围绕原型修改的耻辱并想出一种更有效的新方法!

【讨论】:

    猜你喜欢
    • 2013-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-02
    相关资源
    最近更新 更多