---
description: function's `prototype` property.
---

# prototype

[JS](../..) ⟩ [value](..) ⟩ [object](../obj) ⟩ [function]() ⟩ prototype

{% hint style="success" %}
<mark style="color:red;">**only**</mark>**&#x20;a&#x20;**<mark style="color:yellow;">**relatively small number**</mark>**&#x20;of&#x20;**<mark style="color:yellow;">**objects**</mark> have a "<mark style="color:purple;">**prototype**</mark>" <mark style="color:yellow;">**property**</mark>, it's these objects  that <mark style="color:yellow;">**define**</mark> the [**prototypes**](../obj/proto) for <mark style="color:red;">**all**</mark>**&#x20;**<mark style="color:yellow;">**the other**</mark>**&#x20;objects**.

```javascript
let obj = new F();    // obj.__proto__ === F.prototype
```
{% endhint %}

![](https://2527454625-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MfvEFZnSBhKT6fJmus0%2Fuploads%2FHJM7omWQTKfkuW7WLO59%2Fprototype%20chain%203.png?alt=media\&token=9c375913-41a0-443b-8f90-8d02c24d7c94)

{% tabs %}
{% tab title="⭐️ 重點" %}
{% hint style="danger" %}
:scales: **function's&#x20;**<mark style="color:purple;">**prototype**</mark> <mark style="color:yellow;">**vs.**</mark>**&#x20;class's&#x20;**<mark style="color:purple;">**prototype**</mark> (<mark style="color:yellow;">**property**</mark>)

* [**function**]()'s <mark style="color:purple;">**prototype**</mark> is <mark style="color:green;">**writable**</mark>. (can be reassigned)
* [**class**](../class)'s <mark style="color:purple;">**prototype**</mark>  is <mark style="color:red;">**read-only**</mark>:exclamation:(can't be reassigned)
{% endhint %}

{% hint style="danger" %}
<mark style="color:yellow;">**function's**</mark>**&#x20;**<mark style="color:purple;">**prototype**</mark>**&#x20;**<mark style="color:yellow;">**(property)**</mark>

* is (only) used as a <mark style="color:purple;">**new**</mark> object's [proto](../obj/proto "mention").
* should be either an [**object**](../obj) or <mark style="color:purple;">**null**</mark>, <mark style="color:yellow;">**other values**</mark>**&#x20;**<mark style="color:red;">**won’t work**</mark>:exclamation:

:point\_right: [javascript.info](https://javascript.info/function-prototype)
{% endhint %}

{% hint style="info" %}
⭐️ every **function** has a <mark style="color:yellow;">**default**</mark> <mark style="color:orange;">**prototype**</mark>. (with the **only** <mark style="color:purple;">**constructor**</mark> property that points back to the **function itself**)

```javascript
function A(){}
A.prototype.constructor === A        // true
```

if <mark style="color:purple;">**`A.prototype`**</mark> is an <mark style="color:orange;">**object**</mark>, then <mark style="color:purple;">**`let a = new A()`**</mark> will set <mark style="color:purple;">**`a.__proto__ = A.prototype`**</mark>.
{% endhint %}

{% hint style="danger" %}
⭐️ 注意：

如果<mark style="color:red;">**改寫**</mark>函數的 **prototype**，如：<mark style="color:blue;">`A.prototype = {}`</mark>，則往後的 <mark style="color:blue;">new A()</mark> 物件就再也沒有 <mark style="color:purple;">**constructor**</mark> 屬性，除非你自己在新的 **prototype** 中再加入 <mark style="color:purple;">**constructor**</mark> 屬性❗️(舊的物件沒有影響，因為舊的 prototype 依然存在，舊的物件的 <mark style="color:purple;">`[[Prototype]]`</mark> 屬性沒有改變，依然指向舊的 prototype)
{% endhint %}
{% endtab %}

{% tab title="🔴 主題" %}
* [chain](../obj/proto/chain "mention")
{% endtab %}

{% tab title="👥 相關" %}
* <mark style="color:yellow;">**objects**</mark> created by [**`new F()`**](../obj/create/new) <mark style="color:yellow;">**has**</mark> <mark style="color:purple;">**F.prototype**</mark> <mark style="color:yellow;">**as**</mark> their [**prototype**](../obj/proto).
* object's [proto](../obj/proto "mention") is different from function's [prototype](prototype "mention").
{% endtab %}

{% tab title="💈範例" %}
* [replit](https://replit.com/@pegasusroe/JS-function-prototype#index.js)

```javascript
const { log } = console;
const descriptor = (obj, prop) => log(Object.getOwnPropertyDescriptor(obj, prop));
const descriptors = (obj) => log(Object.getOwnPropertyDescriptors(obj));

// ⭐ function ---------------------------------------------------------

function F(name) {
  this.name = name;
}

descriptors(F);
// property    w e c    value
// ---------------------------------
// length      x x o    1
// name        x x o    'F'
// arguments   x x x    null
// caller      x x x    null              // ------------------------------------
// prototype   o x x    F {} ?  --------> // ⭐ 注意：
// ---------------------------------      //   F.prototype 是 writable❗
// w: writable (can reassign)             //   也就是說，F.prototype 是可以被換掉的❗
// e: enumerable (listed in for loops)    // ------------------------------------
// c: configurable (can delete or change flags)

// ⭐ every function has a default prototype
descriptors(F.prototype);
// property    w e c    value
// -----------------------------------
// constructor o x o    [Function: F]
// -----------------------------------

log(F.prototype.constructor === F);     // true

// new object from F                    // "-->" means "prototype chain"
let obj = new F("object");              // obj --> default prototype
log( obj.eats );                        // `undefined`

// object as new F.prototype
let animal = {
  eats: true
};

// ⭐ overwrite function's default prototype
F.prototype = animal;
log(F.prototype.constructor);                // `Object` (via prototype chain)
log(F.prototype.constructor === Object);     // true

// new object from F (again)
let obj2 = new F("object 2");                // obj2 --> animal 
log( obj2.eats );                            // true

// ⭐ class ---------------------------------------------------------

class A {}

descriptors(A);
// property    w e c    value
// ---------------------------------
// length      x x o    0
// name        x x o    'A'             // ----------------------------------------
// prototype   x x x    A {}   -------> // ⭐ 注意：
// ---------------------------------    //    A.prototype 的 writable == false❗
                                        //    也就是說 A.prototype 是「不能」被換掉的❗
descriptors(A.prototype);               // ----------------------------------------
// property    w e c    value
// -----------------------------------
// constructor o x o    [class A]
// -----------------------------------

const proto = A.prototype;
log( proto === A.prototype );                  // true

// instances of class A
let a = new A();

// ⭐ `A.prototype` is non-writable❗
const newProto = {};

// ----------------------------------------------------------------
A.prototype = newProto;        // ⭐⭐⭐ A.prototype 無法換掉❗❗❗
// ----------------------------------------------------------------

log( A.prototype === newProto );               // ⭐ false❗
log( A.prototype === proto );                  // true
log( A.prototype.constructor );                // [class A]

// console
[
    // `A` is a function.
    A.__proto__ === Function.prototype,        // true
    
    // every function has a "default prototype".
    A.prototype !== null,                      // true
    A.prototype.constructor === A,             // true
    
    // new object's [[Prototype]] is set to `A.prototype` automatically
    a.__proto__ === A.prototype,               // true
    
    // object's constructor can be found through its "prototype chain".
    // (provided its [[Prototype]] hasn't been overridden already)
    a.constructor === A,                       // true
    
].forEach(x => log(x));
```
{% endtab %}

{% tab title="📗 參考" %}
* [ ] JS.info ⟩&#x20;
  * [ ] [Prototypal inheritance](https://javascript.info/prototype-inheritance)
  * [ ] [Native prototypes](https://javascript.info/native-prototypes)
  * [x] [F.prototype](https://javascript.info/function-prototype)
  * [ ] [Prototype methods, objects without \_\_proto\_\_](https://javascript.info/prototype-methods)
{% endtab %}

{% tab title="🗣 討論" %}
* [What is `Function.__proto__`?](https://stackoverflow.com/questions/7688902/what-is-functions-proto)
* [How to change Class's Prototype in ES6](https://stackoverflow.com/questions/37680766/how-to-change-classs-prototype-in-es6)
{% endtab %}

{% tab title="❓" %}
{% hint style="warning" %}
<mark style="color:red;">**問：**</mark>

「 [gas](../../../appendix/gas "mention") 的 classes (如：[Sheet](https://developers.google.com/apps-script/reference/spreadsheet/sheet?hl=en), [Range](https://developers.google.com/apps-script/reference/spreadsheet/range?hl=en) ...) 是否有 prototype」❓
{% endhint %}

{% hint style="success" %}
<mark style="color:green;">答：</mark>

* 「 實驗結果是：<mark style="color:red;">**沒有**</mark> ❗️」
* 「 [Sheet](https://developers.google.com/apps-script/reference/spreadsheet/sheet?hl=en) 物件的 [proto](../obj/proto "mention") 直接連結 <mark style="color:yellow;">**Object.prototype**</mark> 」
{% endhint %}

💾 程式：

```javascript
function test_SheetPrototype() {

  const sheet = app.sheet.active;    // custom getter: returns `Sheeet`
  let obj = sheet;

  while (obj) {

    const keys = Reflect.ownKeys(obj);
    const n = keys.length;
    const k = 3;            // # of sliced items

    log(
      `object: ${obj}` + 
      `, type: ${typeName(obj)}` + 
      `, keys: (${n} items) [${keys.slice(0, k)}${n > k ? ' ...' : ''}]`
    );

    log(keys);              // show all own keys (enum + non-enum + symbol)
    obj = obj.__proto__;    // === Object.getPrototypeOf(obj)
  }
}
```

* 結果 ( [chain](../obj/proto/chain "mention") )

```
object       type       keys
------------------------------------------------------------------
Sheet       object    (141 items) [toString,getFilter,clear ...]
[Object]*   object    ( 12 items) [constructor,__defineGetter__,__defineSetter__ ...]
------------------------------------------------------------------
* last object in the prototype chain === Object.prototype ⭐️ 
```
{% endtab %}
{% endtabs %}

