From 218934fa2ed1c702a6d3923d2aa2cc6b43c48684 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:43:23 -0500 Subject: initial commit --- .../global_objects/object/create/index.html | 406 +++++++++++++++++++++ 1 file changed, 406 insertions(+) create mode 100644 files/uk/web/javascript/reference/global_objects/object/create/index.html (limited to 'files/uk/web/javascript/reference/global_objects/object/create') diff --git a/files/uk/web/javascript/reference/global_objects/object/create/index.html b/files/uk/web/javascript/reference/global_objects/object/create/index.html new file mode 100644 index 0000000000..189aba3ebb --- /dev/null +++ b/files/uk/web/javascript/reference/global_objects/object/create/index.html @@ -0,0 +1,406 @@ +--- +title: Object.create() +slug: Web/JavaScript/Reference/Global_Objects/Object/create +tags: + - ECMAScript 5 + - JavaScript + - 'Null' + - Object + - метод +translation_of: Web/JavaScript/Reference/Global_Objects/Object/create +--- +
{{JSRef}}
+ +

Метод Object.create() створює новий об'єкт, використовуючи існуючий об'єкт як прототип для новоствореного об'єкта.

+ +
{{EmbedInteractiveExample("pages/js/object-create.html")}}
+ + + +

Синтаксис

+ +
Object.create(proto, [propertiesObject])
+ +

Параметри

+ +
+
proto
+
Об'єкт, що має бути прототипом для новоствореного об'єкта.
+
propertiesObject {{Optional_inline}}
+
Якщо вказаний та не дорівнює {{jsxref("undefined")}}, об'єкт, чиї власні перелічувані властивості (тобто, властивості, визначені на самому об'єкті, а не перелічувані властивості, отримані через ланцюжок прототипів) визначають дескриптори властивостей, що мають бути додані до новоствореного об'єкта, з відповідними іменами властивостей. Ці властивості відповідають другому аргументу {{jsxref("Object.defineProperties()")}}.
+
+ +

Значення, що повертається

+ +

Новий об'єкт з зазначеним прототипом та властивостями.

+ +

Винятки

+ +

Виняток {{jsxref("TypeError")}}, якщо параметр propertiesObject дорівнює {{jsxref("null")}} або це об'єкт, що не є обгорткою простого типу.

+ +

Приклади

+ +

Класичне наслідування через Object.create()

+ +

Нижче наведено приклад використання Object.create() для отримання класичного наслідування. Це приклад одиночного наслідування, єдиного, яке підтримує JavaScript.

+ +
// Shape - батьківський клас
+function Shape() {
+  this.x = 0;
+  this.y = 0;
+}
+
+// метод батьківського класу
+Shape.prototype.move = function(x, y) {
+  this.x += x;
+  this.y += y;
+  console.info('Фігуру переміщено.');
+};
+
+// Rectangle - дочірній клас
+function Rectangle() {
+  Shape.call(this); // виклик батьківського конструктора.
+}
+
+// дочірній клас розширює батьківській клас
+Rectangle.prototype = Object.create(Shape.prototype);
+
+//Якщо ви не призначите Object.prototype.constructor значення Rectangle,
+//він візьме prototype.constructor класу Shape (батьківського).
+//Щоб уникнути цього, ми призначаємо prototype.constructor значення Rectangle (дочірній).
+Rectangle.prototype.constructor = Rectangle;
+
+var rect = new Rectangle();
+
+console.log('Чи є rect екземпляром Rectangle?', rect instanceof Rectangle); // true
+console.log('Чи є rect екземпляром Shape?', rect instanceof Shape); // true
+rect.move(1, 1); // Виводить 'Фігуру переміщено.'
+
+ +

Якщо ви бажаєте успадкуватись від кількох об'єктів, можна використати домішки.

+ +
function MyClass() {
+  SuperClass.call(this);
+  OtherSuperClass.call(this);
+}
+
+// успадкувати від одного класу
+MyClass.prototype = Object.create(SuperClass.prototype);
+// змішати з іншим
+Object.assign(MyClass.prototype, OtherSuperClass.prototype);
+// перепризначити конструктор
+MyClass.prototype.constructor = MyClass;
+
+MyClass.prototype.myMethod = function() {
+  // зробити щось
+};
+
+ +

Метод {{jsxref("Object.assign()")}} копіює властивості з прототипу OtherSuperClass у прототип MyClass, роблячи їх доступними для усіх екземплярів MyClass. Object.assign() був запроваджений у ES2015 і може бути відтворений поліфілом. Якщо необхідна підтримка більш старих переглядачів, можна використати jQuery.extend() або _.assign().

+ +

Використання аргументу propertiesObject у Object.create()

+ +
var o;
+
+// створити об'єкт з прототипом null
+o = Object.create(null);
+
+
+o = {};
+// є еквівалентом:
+o = Object.create(Object.prototype);
+
+
+// У цьому прикладі ми створюємо об'єкт з парою
+// зразкових властивостей. (Зауважте, що другий параметр
+// встановлює ключі у відповідності до *дескрипторів властивості*.)
+o = Object.create(Object.prototype, {
+  // foo - це звичайна властивість-значення
+  foo: {
+    writable: true,
+    configurable: true,
+    value: 'hello'
+  },
+  // bar - це властивість-аксесор (має гетер та сетер)
+  bar: {
+    configurable: false,
+    get: function() { return 10; },
+    set: function(value) {
+      console.log('Призначення `o.bar` значення', value);
+    }
+/* з аксесорами ES2015 наш код може виглядати так
+    get() { return 10; },
+    set(value) {
+      console.log('Призначення `o.bar` значення', value);
+    } */
+  }
+});
+
+
+function Constructor() {}
+o = new Constructor();
+// є еквівалентом:
+o = Object.create(Constructor.prototype);
+// Звісно, якщо у функції Constructor присутній
+// код ініціалізації,
+// Object.create() не може його відобразити
+
+
+// Створити новий об'єкт, чиїм прототипом є новий, порожній
+// об'єкт, та додати єдину властивість 'p' зі значенням 42.
+o = Object.create({}, { p: { value: 42 } });
+
+// за замовчуванням властивості НЕДОСТУПНІ для запису,
+// переліку чи налаштування:
+o.p = 24;
+o.p;
+// 42
+
+o.q = 12;
+for (var prop in o) {
+  console.log(prop);
+}
+// 'q'
+
+delete o.p;
+// false
+
+// щоб визначити властивість у ES3
+o2 = Object.create({}, {
+  p: {
+    value: 42,
+    writable: true,
+    enumerable: true,
+    configurable: true
+  }
+});
+/* є еквівалентом:
+o2 = Object.create({p: 42}) */
+
+
+ +

Користувацькі та нульові об'єкти

+ +

Новий об'єкт, створений на основі користувацького об'єкта (особливо об'єкт, створений на основі об'єкта null, який по суті є користувацьким об'єктом, що НЕ МАЄ членів), може поводитись неочікувано. Особливо під час налагодження, оскільки звичайні функції утиліт для перетворення/видалення об'єктних властивостей можуть генерувати помилки або просто втрачати інформацію (особливо якщо використовують перехоплювачі помилок, що ігнорують помилки). Наприклад, ось два об'єкти:

+ +
oco = Object.create( {} );   // створити нормальний об'єкт
+ocn = Object.create( null ); // створити "нульовий" об'єкт
+
+> console.log(oco) // {} -- Виглядає нормально
+> console.log(ocn) // {} -- Поки що теж виглядає нормально
+
+oco.p = 1; // створити просту властивість на нормальному об'єкті
+ocn.p = 0; // створити просту властивість на "нульовому" об'єкті
+
+> console.log(oco) // {p: 1} -- Досі виглядає нормально
+> console.log(ocn) // {p: 0} -- Теж виглядає нормально. АЛЕ СТРИВАЙТЕ...
+
+ +


+ Як показано вище, поки що все виглядає нормальним. Однак, при спробі використати ці об'єкти, їхні відмінності швидко стають очевидними:

+ +
> "oco is: " + oco // виводить "oco is: [object Object]"
+
+> "ocn is: " + ocn // викидає помилку: Cannot convert object to primitive value
+
+ +

Перевірка лише декількох з багатьох базових вбудованих функцій більш чітко демонструє величину проблеми:

+ +
> alert(oco) // виводить [object Object]
+> alert(ocn) // викидає помилку: Cannot convert object to primitive value
+
+> oco.toString() // виводить [object Object]
+> ocn.toString() // викидає помилку: ocn.toString is not a function
+
+> oco.valueOf() // виводить {}
+> ocn.valueOf() // викидає помилку: ocn.valueOf is not a function
+
+> oco.hasOwnProperty("p") // виводить "true"
+> ocn.hasOwnProperty("p") // викидає помилку: ocn.hasOwnProperty is not a function
+
+> oco.constructor // виводить "Object() { [native code] }"
+> ocn.constructor // виводить "undefined"
+
+ +


+ Як вже сказано, ці відмінності можуть швидко зробити процес відлагодження навіть простих на вигляд проблем дуже заплутаним. Наприклад:

+ +

Проста звичайна функція налагодження:

+ +
// вивести пари ключ-значення властивостей верхнього рівня наданого об'єкта
+function ShowProperties(obj){
+  for(var prop in obj){
+    console.log(prop + ": " + obj[prop] + "\n" )
+  }
+}
+ +


+ Не такі прості результати: (особливо якщо перехоплювач помилок сховав повідомлення про помилки)

+ +
ob={}; ob.po=oco; ob.pn=ocn; // створити складний об'єкт з наданих вище тестових об'єктів в якості значень властивостей
+
+> ShowProperties( ob ) // вивести властивості верхнього рівня
+- po: [object Object]
+- Error: Cannot convert object to primitive value
+
+Зауважте, що виводиться тільки перша властивість.
+
+ +


+ (Але якщо такий самий об'єкт був просто створений в іншому порядку -- принаймні, в деяких реалізаціях...)

+ +
ob={}; ob.pn=ocn; ob.po=oco; // створити знову такий самий об'єкт, але створити ті самі властивості в іншому порядку
+
+> ShowProperties( ob ) // вивести властивості верхнього рівня
+- Error: Cannot convert object to primitive value
+
+Зауважте, що жодна властивість не виводиться.
+ +

Зауважте, що такий відмінний порядок може виникнути статично, через відмінний зафіксований код, як ось тут, а може й динамічно, через порядок, в якому виконуються під час запуску гілки коду з додаванням властивостей, що залежить від вхідних даних та/або випадкових змінних. Знову ж таки, реальний порядок перебору не гарантований, в якому б порядку не додавалися члени об'єкта.

+ +

Деякі рішення, що не працюють

+ +

Гарне вирішення проблеми відсутніх об'єктних методів не завжди є очевидним.

+ +

Пряме додавання відсутнього об'єктного метода зі стандартного об'єкта НЕ працює:

+ +
ocn = Object.create( null ); // створити "нульовий" об'єкт (такий самий, як і раніше)
+
+ocn.toString = Object.toString; // оскільки йому бракує методу, призначити його прямо зі стандартного об'єкта
+
+> ocn.toString // виводить "toString() { [native code] }" -- схоже, що відсутній метод тепер додано
+> ocn.toString == Object.toString // виводить "true" -- схоже, це той самий метод, що й у стандартному об'єкті
+
+> ocn.toString() // error: Function.prototype.toString requires that 'this' be a Function
+
+ +


+ Пряме додавання відсутнього об'єктного метода у "прототип" нового об'єкта також не працює, оскільки у нового об'єкта немає справжнього прототипа (що й є справжньою причиною УСІХ цих проблем), і його не можна додати прямо:

+ +
ocn = Object.create( null ); // створити "нульовий" об'єкт (такий самий, як і раніше)
+
+ocn.prototype.toString = Object.toString; // Error: Cannot set property 'toString' of undefined
+
+ocn.prototype = {};                       // спробувати створити прототип
+ocn.prototype.toString = Object.toString; // оскільки об'єкту бракує методу, призначити його прямо зі стандартного об'єкта
+
+> ocn.toString() // error: ocn.toString is not a function
+
+ +


+ Додавання відсутнього об'єктного метода використанням стандартного об'єкта в якості прототипа нового об'єкта також не працює:

+ +
ocn = Object.create( null );        // створити "нульовий" об'єкт (такий самий, як і раніше)
+Object.setPrototypeOf(ocn, Object); // встановити значенням прототипу нового об'єкта стандартний об'єкт
+
+> ocn.toString() // error: Function.prototype.toString requires that 'this' be a Function
+
+ +

Деякі вдалі рішення

+ +

Як вже сказано, пряме додавання відсутнього об'єктного методу зі стандартного об'єкта НЕ працює. Однак, пряме додавання загального метода ПРАЦЮЄ:

+ +
ocn = Object.create( null ); // створити "нульовий" об'єкт (такий самий, як і раніше)
+
+ocn.toString = toString; // оскільки об'єкту бракує методу, призначити його прямо з загальної версії
+
+> ocn.toString() // виводить "[object Object]"
+> "ocn is: " + ocn // виводить "ocn is: [object Object]"
+
+
+ob={}; ob.pn=ocn; ob.po=oco; // створити складний об'єкт (такий самий, як і раніше)
+
+> ShowProperties(ob) // вивести властивості верхнього рівня
+- po: [object Object]
+- pn: [object Object]
+
+ +

Однак, встановлення загального прототипу прототипом нового об'єкта працює навіть краще:

+ +
ocn = Object.create( null );                  // створити "нульовий" об'єкт (такий самий, як і раніше)
+Object.setPrototypeOf(ocn, Object.prototype); // встановити значенням прототипу нового об'єкта "загальний" об'єкт (НЕ стандартний об'єкт)
+
+ +

(На додачу до функцій, пов'язаних з рядками, що наведені вище, це також додає:)

+ +
> ocn.valueOf() // виводить {}
+> ocn.hasOwnProperty("x") // виводить "false"
+> ocn.constructor // виводить "Object() { [native code] }"
+
+// ...та вся решта властивостей та методів Object.prototype.
+
+ +

Як бачимо, об'єкти, змінені таким чином, тепер виглядають дуже схожими на звичайні об'єкти.

+ +

Поліфіл

+ +

Цей поліфіл покриває основний сценарій використання, а саме, створення нового об'єкта, для якого був обраний прототип, але не бере до уваги другий аргумент.

+ +

Зауважте, що в той час як використання null в якості [[Prototype]] підтримується в реальному методі ES5 Object.create, цей поліфіл не може це підтримувати через обмеження, притаманне версіям ECMAScript нижче 5.

+ +
 if (typeof Object.create !== "function") {
+    Object.create = function (proto, propertiesObject) {
+        if (typeof proto !== 'object' && typeof proto !== 'function') {
+            throw new TypeError("Прототипом об'єкта може бути тільки об'єкт: " + proto);
+        } else if (proto === null) {
+            throw new Error("Реалізація Object.create у цьому браузері є шимом та не підтримує 'null' в якості першого аргументу.");
+        }
+
+        if (typeof propertiesObject != 'undefined') {
+            throw new Error("Реалізація Object.create у цьому браузері є шимом та не підтримує другий аргумент.");
+        }
+
+        function F() {}
+        F.prototype = proto;
+
+        return new F();
+    };
+}
+
+ +

Специфікації

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
СпецифікаціяСтатусКоментар
{{SpecName('ES5.1', '#sec-15.2.3.5', 'Object.create')}}{{Spec2('ES5.1')}}Початкове визначення. Реалізоване у JavaScript 1.8.5.
{{SpecName('ES2015', '#sec-object.create', 'Object.create')}}{{Spec2('ES2015')}}
{{SpecName('ESDraft', '#sec-object.create', 'Object.create')}}{{Spec2('ESDraft')}}
+ +

Сумісність з веб-переглядачами

+ +
+ + +

{{Compat("javascript.builtins.Object.create")}}

+
+ +

Див. також

+ + -- cgit v1.2.3-54-g00ecf