Что происходит при вызове Object.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 уже появляется на самом внешнем уровне?

Похоже, console.dir запутался. Это ошибка. x не является собственностью foo.

Bergi 17.12.2018 19:41

классно.........!

Basheer Kharoti 19.12.2018 08:34
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
5
3
309
1

Ответы 1

Что случилось (шаг за шагом)

var Foo = function(){};

Определена новая функция с именем - Foo. Если мы воспользуемся console.dir(Foo), мы увидим, что Foo имеет 2 специальных члена: prototype и __proto__.

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

Обновлен прототип Foo. О defineProperty (от MDN):

The static method Object.defineProperty() defines a new property directly on an object, or modifies an existing property on an object, and returns the object.

Итак, объект prototype теперь изменен новым членом с именем x. prototype здесь действует как c'tor и "запускается", когда будет создан новый экземпляр Foo.

var foo = new Foo();

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

Альтернативы

Расширение 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;
       }
    });
}

«вы используете объект Foo.prototype (как функцию)» - нет? И это даже невозможно, так как Foo.prototype не является функцией!

Bergi 17.12.2018 19:43
Foo.__proto__ - это просто Function.prototype. Как вы сказали, добавление свойств не повлияет на объекты, созданные из Foo, но вы, похоже, упустили, что это повлияет на каждую отдельную функцию. После расширения Foo.__proto__ попробуйте console.info(function(){}.x);
Paul 18.12.2018 01:07

Другие вопросы по теме