Что происходит, когда вызывается Object.defineProperty для прототипа функции? - PullRequest
0 голосов
/ 17 декабря 2018
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 голосов
/ 17 декабря 2018

Что случилось (пошагово)

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 здесь действует как c'tor и «стартует», когда будет создан новый экземпляр Foo

var foo = new Foo();

Создан новый экземпляр Foo.вызов c'tor использует прототип Foo и применяется x getter

Alternatives

Extennding 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 и почему это происходит

Оригинальный ответ

Это происходит потому, что в 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. Ваш прототип функции будет изменен вашим новым получателем
  2. Каждый новый объект (который наследует) из вашего класса будеттакже используйте ваш новый метод получения (на уровне объекта)

Я действительно думаю, что ваш код должен выглядеть примерно так:

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