mozilla

Revision 542065 of Object.setPrototypeOf()

  • Revision slug: Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf
  • Revision title: Object.setPrototypeOf()
  • Revision id: 542065
  • Created:
  • Creator: ziyunfei
  • Is current revision? No
  • Comment

Revision Content

{{JSRef("Global_Objects", "Object")}} {{harmony()}}

Summary

Mutating the [[Prototype]] of an object, using either this method or the deprecated {{jsxref("Object.proto", "Object.prototype.__proto__")}}, is strongly discouraged, because it is very slow and unavoidably slows down subsequent execution in modern JavaScript implementations.

The Object.setPrototype() method sets the prototype (i.e., the internal [[Prototype]] property ) of a specified object to another object or null.

Syntax

Object.setPrototypeOf(obj, prototype);

Parameters

obj
The object which is to have its prototype set.
prototype
The object's new prototype (an object or null).

Description

Throws a {{jsxref("Global_Objects/TypeError", "TypeError")}} exception if the object whose [[Prototype]] is to be modified is non-extensible according to {{jsxref("Object.isExtensible")}}.  Does nothing if the prototype parameter isn't an object or null (i.e., number, string, boolean, or undefined).  Otherwise, this method changes the [[Prototype]] of obj to the new value.

Mutating the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation.  If you care at all about performance, you should never mutate the [[Prototype]] of an object, either using this method or using {{jsxref("Object.setPrototypeOf")}}.  Instead, create the object with the desired [[Prototype]] using {{jsxref("Object.create")}}.

Object.setPrototypeOf() is in the latest ECMAScript 6 standard draft.

Examples

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

Polyfill

Using the old and deprecated {{jsxref("Object.proto", "Object.prototype.__proto__")}} property, we can easily define Object.setPrototypeOf if it isn't available already:

Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
  obj.__proto__ = proto;
  return obj; 
}

Appending a whole prototype chain to a new prototype object

A combination of Object.getPrototypeOf() and {{jsxref("Object.proto", "Object.prototype.__proto__")}} permits appending a whole prototype chain to a new prototype object:

/**
*** Object.setPrototypeOf(@object, @prototype)
* Changes the prototype of an instance
*
**/

Object.setPrototypeOf = function (oInstance, oProto) {
  oInstance.__proto__ = oProto;
  return oInstance;
};

/**
*** Object.appendChain(@object, @prototype)
*
* Appends the first non-native prototype of a chain to a new prototype.
* Returns @object (if it was a primitive value it will transformed into an 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")
*
* Appends the first non-native prototype of a chain to the native Function.prototype object, then appends a
* new Function(["@arg"(s)], "@function_body") to that chain.
* Returns the function.
*
**/

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;
}

Usage

// First example: appending a chain to a prototype

function Mammal () {
  this.isMammal = "yes";
}

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

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

var oCat = new MammalSpecies("Felis");

alert(oCat.isMammal); // "yes"

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

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

alert(oCat.breathing); // "yes"

// Second example: transforming a primitive value into an instance of its constructor and append its chain to a prototype

function Symbol () {
  this.isSymbol = "yes";
}

var nPrime = 17;

alert(typeof nPrime); // "number"

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

alert(oPrime); // "17"
alert(oPrime.isSymbol); // "yes"
alert(typeof oPrime); // "object"

// Third example: appending a chain to the Function.prototype object and appending a new function to that chain

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

var george = Object.appendChain(new Person("George"), "alert(\"Hello guys!!\");");

alert(george.identity); // "George"
george(); // "Hello guys!!"

Specifications

Specification Status Comment
{{SpecName('ES6', '#sec-object.setprototypeof', 'Object.setProtoypeOf')}} {{Spec2('ES6')}} Initial definition.

Browser compatibility

{{ CompatibilityTable() }}

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support 34
See Issue 2675
{{ CompatGeckoDesktop(31) }}
See {{bug("885788")}}
{{ CompatNo() }} {{ CompatNo() }} {{ CompatNo() }}
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support {{ CompatNo() }} {{ CompatNo() }} {{ CompatGeckoMobile(31) }}
See {{bug("885788")}}
{{ CompatNo() }} {{ CompatNo() }} {{ CompatNo() }}

See also

  • {{jsxref("Object.prototype.isPrototypeOf")}}
  • {{jsxref("Object.getPrototypeOf")}}

Revision Source

<div>
 <div>
  {{JSRef("Global_Objects", "Object")}} {{harmony()}}</div>
</div>
<h2 id="Summary" name="Summary">Summary</h2>
<div class="warning">
 <p>Mutating the <code>[[Prototype]]</code> of an object, using either this method or the deprecated {{jsxref("Object.proto", "Object.prototype.__proto__")}}, is strongly discouraged, because it is very slow and unavoidably slows down subsequent execution in modern JavaScript implementations.</p>
</div>
<p>The <code><strong>Object.setPrototype()</strong></code> method sets the prototype (i.e., the internal <code>[[Prototype]] </code>property ) of a specified object to another object or <code>null</code>.</p>
<h2 id="Syntax" name="Syntax">Syntax</h2>
<pre class="syntaxbox">
<code>Object.setPrototypeOf(<em>obj, prototype</em>);</code></pre>
<h3 id="Parameters" name="Parameters">Parameters</h3>
<dl>
 <dt>
  obj</dt>
 <dd>
  The object which is to have its prototype set.</dd>
 <dt>
  prototype</dt>
 <dd>
  The object's new prototype (an object or <code>null</code>).</dd>
</dl>
<h2 id="Description" name="Description">Description</h2>
<p>Throws a {{jsxref("Global_Objects/TypeError", "TypeError")}} exception if the object whose [[Prototype]] is to be modified is non-extensible according to {{jsxref("Object.isExtensible")}}.&nbsp; Does nothing if the prototype parameter isn't an object or <code>null</code> (i.e., number, string, boolean, or undefined).&nbsp; Otherwise, this method changes the <code>[[Prototype]]</code> of <code>obj</code> to the new value.</p>
<div class="warning">
 <p>Mutating the <code>[[Prototype]]</code> of an object is, by the nature of how modern JavaScript engines optimize property accesses, a very slow operation.&nbsp; If you care at all about performance, you should never mutate the <code>[[Prototype]]</code> of an object, either using this method or using {{jsxref("Object.setPrototypeOf")}}.&nbsp; Instead, create the object with the desired <code>[[Prototype]]</code> using {{jsxref("Object.create")}}.</p>
</div>
<p><code>Object.setPrototypeOf()</code> is in the latest ECMAScript 6 standard draft.</p>
<h2 id="Notes" name="Notes">Examples</h2>
<pre class="brush: js">
var dict = Object.setPrototypeOf({}, null);
</pre>
<h2 id="Notes" name="Notes">Polyfill</h2>
<p>Using the old and deprecated {{jsxref("Object.proto", "Object.prototype.__proto__")}} property, we can easily define <code>Object.setPrototypeOf</code>&nbsp;if it isn't available already:</p>
<pre class="brush: js">
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
  obj.__proto__ = proto;
  return obj; 
}</pre>
<h3 id="Appending_a_whole_prototype_chain_to_a_new_prototype_object">Appending a whole prototype chain to a new prototype object</h3>
<p>A combination of <code>Object.getPrototypeOf()</code> and {{jsxref("Object.proto", "Object.prototype.__proto__")}} permits appending a whole prototype chain to a new prototype object:</p>
<pre class="brush: js">
/**
*** Object.setPrototypeOf(@object, @prototype)
* Changes the prototype of an instance
*
**/

Object.setPrototypeOf = function (oInstance, oProto) {
  oInstance.__proto__ = oProto;
  return oInstance;
};

/**
*** Object.appendChain(@object, @prototype)
*
* Appends the first non-native prototype of a chain to a new prototype.
* Returns @object (if it was a primitive value it will transformed into an 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")
*
* Appends the first non-native prototype of a chain to the native Function.prototype object, then appends a
* new Function(["@arg"(s)], "@function_body") to that chain.
* Returns the function.
*
**/

Object.appendChain = function (oChain, oProto) {
  if (arguments.length &lt; 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 &amp;&amp; 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;
}
</pre>
<h4 id="Usage">Usage</h4>
<pre class="brush: js">
// First example: appending a chain to a prototype

function Mammal () {
  this.isMammal = "yes";
}

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

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

var oCat = new MammalSpecies("Felis");

alert(oCat.isMammal); // "yes"

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

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

alert(oCat.breathing); // "yes"

// Second example: transforming a primitive value into an instance of its constructor and append its chain to a prototype

function Symbol () {
  this.isSymbol = "yes";
}

var nPrime = 17;

alert(typeof nPrime); // "number"

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

alert(oPrime); // "17"
alert(oPrime.isSymbol); // "yes"
alert(typeof oPrime); // "object"

// Third example: appending a chain to the Function.prototype object and appending a new function to that chain

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

var george = Object.appendChain(new Person("George"), "alert(\"Hello guys!!\");");

alert(george.identity); // "George"
george(); // "Hello guys!!"</pre>
<h2 id="Specifications">Specifications</h2>
<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">Specification</th>
   <th scope="col">Status</th>
   <th scope="col">Comment</th>
  </tr>
  <tr>
   <td>{{SpecName('ES6', '#sec-object.setprototypeof', 'Object.setProtoypeOf')}}</td>
   <td>{{Spec2('ES6')}}</td>
   <td>Initial definition.</td>
  </tr>
 </tbody>
</table>
<h2 id="Browser_compatibility">Browser compatibility</h2>
<p>{{ CompatibilityTable() }}</p>
<div id="compat-desktop">
 <table class="compat-table">
  <tbody>
   <tr>
    <th>Feature</th>
    <th>Chrome</th>
    <th>Firefox (Gecko)</th>
    <th>Internet Explorer</th>
    <th>Opera</th>
    <th>Safari</th>
   </tr>
   <tr>
    <td>Basic support</td>
    <td>34<br />
     See <a href="https://code.google.com/p/v8/issues/detail?id=2675">Issue 2675</a></td>
    <td>{{ CompatGeckoDesktop(31) }}<br />
     See {{bug("885788")}}</td>
    <td>{{ CompatNo() }}</td>
    <td>{{ CompatNo() }}</td>
    <td>{{ CompatNo() }}</td>
   </tr>
  </tbody>
 </table>
</div>
<div id="compat-mobile">
 <table class="compat-table">
  <tbody>
   <tr>
    <th>Feature</th>
    <th>Android</th>
    <th>Chrome for Android</th>
    <th>Firefox Mobile (Gecko)</th>
    <th>IE Mobile</th>
    <th>Opera Mobile</th>
    <th>Safari Mobile</th>
   </tr>
   <tr>
    <td>Basic support</td>
    <td>{{ CompatNo() }}</td>
    <td>{{ CompatNo() }}</td>
    <td>{{  CompatGeckoMobile(31) }}<br />
     See {{bug("885788")}}</td>
    <td>{{ CompatNo() }}</td>
    <td>{{ CompatNo() }}</td>
    <td>{{ CompatNo() }}</td>
   </tr>
  </tbody>
 </table>
</div>
<h2 id="See_also" name="See_also">See also</h2>
<ul>
 <li>{{jsxref("Object.prototype.isPrototypeOf")}}</li>
 <li>{{jsxref("Object.getPrototypeOf")}}</li>
</ul>
Revert to this revision