> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/web/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/web/js/val/obj/proto/chain/print.md).

# printPrototypeChain()

🚧 under construction -> improve with TableMaker, make it a method.

[JS](/web/js.md) ⟩ [types](/web/js/val/type.md) ⟩ [object](broken://pages/c3kdqarPVmCRDuMeH3s5) ⟩ [prototype chain](/web/js/val/obj/proto/chain.md) ⟩ print

{% tabs %}
{% tab title="💾 程式" %}

* replit： [printPrototypeChainOf()](https://replit.com/@pegasusroe/log-prototype-chain#prototypeChain.js)
* require： [Iterator](/web/js/iteration/iterator/iterator.md), [isPrimitive()](/web/js/val/type/type-functions/isprimitive.md), [typeName()](/web/js/val/type/name/typename.md), [TableMaker](/web/appendix/custom/class/tablemaker.md)

```javascript
// importimport
const Iterator = require('./IteratorPrototype.js');
const { isPrimitive } = require('./isObject.js');
const { typeName } = require('./typeNames.js');
const { log } = console;

// ⭐️ prototype chain of value
function printPrototypeChainOf(value, name, {
    
    typeWidth=12,     // "type" column width
    noteWidth=23,     // "note" column width
    valueWidth=28,    // "value" column width
    
    prototypes=[],    // custom prototypes, format:
                      // {value: <value>, name: <name>}
}={}) {
    
    // if not an object, do nothing
    if (isPrimitive(value)) {
        log(`ℹ️ value: ${value} is not an object.`);
        return;
    }

    // keep the original object for reference
    const original = value;

    // column widths
    const widths = {
        
        type: typeWidth,
        note: noteWidth,
        value: valueWidth,
        
        cols: 3,        // # of columns
        pad: 1,
            
            
        get total() {
            return this.type + this.note + this.value + (this.cols - 1) * this.pad
        }
    };

    // separator line
    const line = '-'.repeat(widths.total);
    const arrow = '→ ';
    
    // 🔸 print row
    function print(type, note='', value='') {
        
        const items = [
            type.padEnd(widths.type, ' '),
            note.padEnd(widths.note, ' '),
            value,
        ];
        
        log(...items);
    }

    // table header
    log(`🌟 Prototype Chain of: `, name);
    log(line);
    print(`  type`, `prototype chain`, `value`);
    log(line);

    // 🌟 builtin prototypes
    const builtinPrototypes = [
        {value: Object.prototype, name: 'Object.prototype', hideValue: true},
        {value: Array.prototype, name: 'Array.prototype', hideValue: true},
        {value: Function.prototype, name: 'Function.prototype', hideValue: true},
        {value: Iterator.prototype, name: 'Iterator.prototype', hideValue: true},
    ];

    // 🔸 known prototype ?
    function proto(obj) {

        prototypes = builtinPrototypes.concat(prototypes);
        type = '• ' + typeName(obj);
        
        const result = {type: type, name: '(?)', value: obj }
        
        // test for prototypes
        for (const p of prototypes) {
            if (p.value === obj) {
                result.name = p.name;
                if (p.hideValue) result.value = '';
                break;
            }
        }

        result.name = arrow + result.name;
        return result;
    }

    // while value !== null, print it out
    while (value) {
        let p = proto(value);
        if (value === original) p.name = name;
        print(p.type, p.name, p.value);
        value = Object.getPrototypeOf(value);
    }

    // now, value === null
    print(`• Null`, arrow + '❌', 'null');
    log(line+'\n');
    
}

// export
module.exports = {printPrototypeChainOf};
```

{% endtab %}

{% tab title="💈範例" %}

* replit： [printPrototypeChainOf()](https://replit.com/@pegasusroe/log-prototype-chain#prototypeChain.js)

```javascript
// import
const { printPrototypeChainOf } = require('./prototypeChain.js');

// object literal
var obj = {a:1};

// custom classes
class A {}
class B extends A {};

let a = new A();
let b = new B();

// generator function
function* gen(){}

// log
[
    {value: obj, name: 'obj'},
    {value: [1,2], name: '[1,2]'},
    {value: function foo(){}, name: 'foo'},
    {value: gen(), name: 'gen()'},

    {value: a, name: 'new A()'},
    {value: b, name: 'new B()'},
    
].forEach(x => 
    printPrototypeChainOf(x.value, x.name, {
        // typeWidth: 15,
        // valueWidth: 28,
        prototypes: [
            {value: A.prototype, name: 'A.prototype', hideValue: true},
            {value: B.prototype, name: 'B.prototype', hideValue: true},
        ]
    })
);
```

{% endtab %}

{% tab title="📃 結果" %}

* replit： [printPrototypeChainOf()](https://replit.com/@pegasusroe/log-prototype-chain#prototypeChain.js),   (require：[TableMaker](/web/appendix/custom/class/tablemaker.md))

```javascript
🌟 Prototype Chain of:  obj
-----------------------------------------------------------------
  type       prototype chain         value
-----------------------------------------------------------------
• Object     obj                     { a: 1 }
• Object     → Object.prototype      
• Null       → ❌                     null
-----------------------------------------------------------------

🌟 Prototype Chain of:  [1,2]
-----------------------------------------------------------------
  type       prototype chain         value
-----------------------------------------------------------------
• Array      [1,2]                   [ 1, 2 ]
• Array      → Array.prototype       
• Object     → Object.prototype      
• Null       → ❌                     null
-----------------------------------------------------------------

🌟 Prototype Chain of:  foo
-----------------------------------------------------------------
  type       prototype chain         value
-----------------------------------------------------------------
• Function   foo                     [Function: foo]
• Function   → Function.prototype    
• Object     → Object.prototype      
• Null       → ❌                     null
-----------------------------------------------------------------

🌟 Prototype Chain of:  gen()
-----------------------------------------------------------------
  type       prototype chain         value
-----------------------------------------------------------------
• Generator  gen()                   Object [Generator] {}
• Generator  → (?)                   Object [Generator] {}
• Generator  → (?)                   Object [Generator] {}
• Object     → Iterator.prototype    
• Object     → Object.prototype      
• Null       → ❌                     null
-----------------------------------------------------------------

🌟 Prototype Chain of:  new A()
-----------------------------------------------------------------
  type       prototype chain         value
-----------------------------------------------------------------
• Object     new A()                 A {}
• Object     → A.prototype           
• Object     → Object.prototype      
• Null       → ❌                     null
-----------------------------------------------------------------

🌟 Prototype Chain of:  new B()
-----------------------------------------------------------------
  type       prototype chain         value
-----------------------------------------------------------------
• Object     new B()                 B {}
• Object     → B.prototype           
• Object     → A.prototype           
• Object     → Object.prototype      
• Null       → ❌                     null
-----------------------------------------------------------------
```

{% endtab %}

{% tab title="🛠 工具" %}

* [ObjectPlayground](http://www.objectplayground.com/) - visualize prototype chain (cool ⭐️)
  {% endtab %}

{% tab title="🗣 討論" %}

* [A function to print prototype chain for a given object](https://stackoverflow.com/questions/22168033/a-function-to-print-prototype-chain-for-a-given-object)
  {% endtab %}
  {% endtabs %}
