Object.setPrototypeOf()
=======================

**Предупреждение:** Изменение прототипа `[[Prototype]]` объекта является, по самой природе оптимизации доступа к свойствам в современных движках JavaScript, очень медленной операцией, это справедливо для ***любого*** браузера и движка JavaScript. Изменение прототипов очень тонко и обширно влияет на производительность, причём это влияние не ограничивается просто временем, проведённым внутри метода `Object.setPrototypeOf()`, оно может распространяться на ***любой*** код, который имеет доступ к ***любому*** объекту, чей прототип `[[Prototype]]` был изменён. Если вы заботитесь о производительности, вы никогда не должны изменять прототип `[[Prototype]]` объекта. Вместо этого создайте объект с нужным прототипом `[[Prototype]]`, с помощью метода `Object.create()`.

Сводка
------

Метод **`Object.setPrototypeOf()`** устанавливает прототип (то есть, внутреннее свойство `[[Prototype]]`) указанного объекта в другой объект или `null`.

Синтаксис
---------
```

Object.setPrototypeOf(obj, prototype);
```

### Параметры

`obj`

Объект, которому устанавливается прототип.

`prototype`

Новый прототип объекта (объект или `null`).

Описание
--------

Выкидывает исключение `TypeError`, если объект, чей прототип `[[Prototype]]` является не расширяемым, согласно методу `Object.isExtensible()`. Не делает ничего, если параметр `prototype` не является объектом или значением `null` (то есть, является числом, строкой, логическим значением или `undefined`). В противном случае метод устанавливает прототип `[[Prototype]]` объекта `obj` в новое значение.

Примеры
-------


```js
var dict = Object.setPrototypeOf({}, null);
```

Полифил
-------

Используя старое свойство `Object.prototype.__proto__`, мы можем легко определить `Object.setPrototypeOf()`, если он ещё не доступен:


```js
if (!Object.setPrototypeOf) {
  Object.prototype.setPrototypeOf = function (obj, proto) {
    if (obj.__proto__) {
      obj.__proto__ = proto;
      return obj;
    } else {
      // Если нужно будет определить прототип у Object.create(null) объекта
      var Fn = function () {
        for (var key in obj) {
          //Если в объект уже были определены некоторые свойства
          Object.defineProperty(this, key, {
            value: obj[key],
          });
        }
      };
      Fn.prototype = proto;
      return new Fn();
    }
  };
}
```

Добавление цепочки прототипов
-----------------------------

Сочетание метода `Object.getPrototypeOf()` и свойства `Object.prototype.__proto__` позволяет добавить целую цепочку прототипов к новому прототипу объекта:


```js
/\*\*
 \*\*\* Object.appendChain(@object, @prototype)
 \*
 \* Присоединяет первый неродной прототип цепочки к новому прототипу.
 \* Возвращает @object (если он был примитивным значением, оно будет преобразовано в объект).
 \*
 \*\*\* Object.appendChain(@object [, "@arg\_name\_1", "@arg\_name\_2", "@arg\_name\_3", "..."], "@function\_body")
 \*\*\* Object.appendChain(@object [, "@arg\_name\_1, @arg\_name\_2, @arg\_name\_3, ..."], "@function\_body")
 \*
 \* Присоединяет первый не родной прототип цепочки к родному объекту Function.prototype, затем присоединяет
 \* new Function(["@arg"(s)], "@function\_body") к этой цепочке.
 \* Возвращает функцию.
 \*
 \*\*/

Object.appendChain = function (oChain, oProto) {
  if (arguments.length < 2) {
    throw new TypeError("Object.appendChain - Not enough arguments");
  }
  if (typeof oProto === "number" || typeof oProto === "boolean") {
    throw new TypeError(
      "second argument to Object.appendChain must be an object or a string",
    );
  }

  var oNewProto = oProto,
    oReturn =
      (o2nd =
      oLast =
        oChain instanceof this ? oChain : new oChain.constructor(oChain));

  for (
    var o1st = this.getPrototypeOf(o2nd);
    o1st !== Object.prototype && o1st !== Function.prototype;
    o1st = this.getPrototypeOf(o2nd)
  ) {
    o2nd = o1st;
  }

  if (oProto.constructor === String) {
    oNewProto = Function.prototype;
    oReturn = Function.apply(null, Array.prototype.slice.call(arguments, 1));
    this.setPrototypeOf(oReturn, oLast);
  }

  this.setPrototypeOf(o2nd, oNewProto);
  return oReturn;
};
```

### Использование

#### Первый пример: присоединение цепочки к прототипу


```js
function Mammal() {
  this.isMammal = "да";
}

function MammalSpecies(sMammalSpecies) {
  this.species = sMammalSpecies;
}

MammalSpecies.prototype = new Mammal();
MammalSpecies.prototype.constructor = MammalSpecies;

var oCat = new MammalSpecies("Felis");

alert(oCat.isMammal); // 'да'

function Animal() {
  this.breathing = "да";
}

Object.appendChain(oCat, new Animal());

alert(oCat.breathing); // 'да'
```


#### Второй пример: преобразование примитивного значения в экземпляр его конструктора и присоединение его цепочки к прототипу


```js
function Symbol() {
  this.isSymbol = "да";
}

var nPrime = 17;

alert(typeof nPrime); // 'number'

var oPrime = Object.appendChain(nPrime, new Symbol());

alert(oPrime); // '17'
alert(oPrime.isSymbol); // 'да'
alert(typeof oPrime); // 'object'
```


#### Третий пример: присоединение цепочки к объекту `Function.prototype` и новой функции к этой цепочке


```js
function Person(sName) {
  this.identity = sName;
}

var george = Object.appendChain(
  new Person("Георг"),
  'alert("Привет, парни!!");',
);

alert(george.identity); // 'Георг'
george(); // 'Привет, парни!!'
```

Спецификации
------------

| Specification |
| --- |
| ECMAScript Language Specification # sec-object.setprototypeof |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* `Object.prototype.isPrototypeOf()`
* `Object.getPrototypeOf()`
* `Object.prototype.__proto__`