为函数的原型调用Object.defineProperty时会发生什么?

时间:2018-12-17 13:14:35

标签: javascript get prototype getter defineproperty

var Foo = function(){};

Object.defineProperty(Foo.prototype,'x',{
    get(){
        return 3;
    }
});

var foo = new Foo();

console.dir(foo);

我想要的结果应该是

Foo {
    __proto__:{
        constructor: ƒ (),
        x: 3,
        __proto__: Object
    }
}

但是真正的结果是

Foo {
    x: 3,
    __proto__:{
        constructor: ƒ (),
        x: 3,
        __proto__: Object
    }
}

为什么x属性已经出现在最外层?

1 个答案:

答案 0 :(得分:-2)

发生了什么(逐步)

var Foo = function(){};

定义了一个新函数,名为-Foo。如果我们使用console.dir(Foo),我们将看到Foo有2个特殊成员prototype__proto__

Object.defineProperty(Foo.prototype,'x',{
    get(){
        return 3;
    }
}); 

Foo的原型已更新。关于defineProperty(来自MDN):

  

静态方法Object.defineProperty()定义了一个新属性   直接在对象上,或修改对象上的现有属性,   并返回对象。

因此prototype对象现在被一个名为x的新成员修改了。 prototype在这里充当角色,并且在创建Foo的新实例时将“启动”

var foo = new Foo();

创建了一个新的Foo实例。 c'tor调用使用的是Foo原型,并且应用了x getter

替代项

扩展Foo prototype,从而确保它仅影响从Foo创建的对象(作为一个类)

Object.defineProperty(Foo.prototype, 'x',
{
    get: () => 3
}); 

console.dir(new Foo().x) // will show 3
console.dir(Foo.x) // undefined - protorype is for class objects

或扩展Foo __proto__,从而将Foo作为函数进行更新,同时不影响由此创建的对象

Object.defineProperty(Foo.__proto__, 'x',
{
    get: () => 3
}); 

console.dir(new Foo().x) // undefined - x is not a member of Foo
console.dir(Foo.x) // 3

奖金:关于JS原型及其发生原因的很好的article

原始答案

之所以会这样,是因为在JS function中,这是一种同时声明函数和类的方法!

因此,您的Foo函数也可以用作类

var Foo = function(){};
Foo(); // call Foo as a function
var obj = new Foo(); // initiate an instance from class Foo

因为您正在使用Foo.prototype对象(作为函数),然后从Foo类创建新实例,所以可以保证:

  1. 您的函数原型将使用新的getter进行修改
  2. 从类中继承的每个新对象也将使用新的getter(在对象级别)

我真的认为您的代码应该是这样的:

function Foo ()
{
    Object.defineProperty(this,'x',{
       get(){
           return 3;
       }
    });
}