JS:prototype chain

5/14/2019 JS

# JS:prototype chain

# 定义

每个JS对象都有一个prototype,这个prototype又有自己的prototype,以此类推直到某个对象的prototype 是null为止,一个一个串成链

# 获取

  • ECMA2015:Object.getPrototypeOf(),对应的是Object.setPrototypeOf()
  • 大部分浏览器实现:Object._proto_

# 注意点

  1. 函数的func.prototype表示的是当此函数作为构造器时,构造的对象对应的prototype链接
let f1 = function () {
    this.a = 1;
    this.b = 2
}
let obj1 = new f1();
console.log(Object.getPrototypeOf(obj1));// f1{}
console.log(obj1.a);//1
console.log(obj1.c);// undefined
f1.prototype.c = 3;
console.log(obj1.a);//1
console.log(obj1.c);//3
1
2
3
4
5
6
7
8
9
10
11

# 继承到的“方法”

当一个对象继承到的方法被执行时,方法内部的this指向的是当前继承到方法的对象

let animal = {
    name: 'animal',
    getName: function () {
        return this.name;
    },
    getNameArrow: () => {
        return this.name
    }
}
console.log(animal.getName()); // animal
console.log(animal.getNameArrow()); // undefined,因为箭头函数定义时的上下文为全局作用域
let cat = Object.create(animal);
cat.name = 'cat'
console.log(cat.getName()); // cat
console.log(cat.getNameArrow()); // undefined,因为箭头函数定义时的上下文为全局作用域
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 使用原型链

  1. 函数原型作为构造器

    function animal() {}
    animal.prototype.name = 'noname'
    let cat = new animal()
    console.log(cat.name);// noname
    
    1
    2
    3
    4
  2. 函数原型上的属性会被以函数作为构造器的实例类获取

function gen1() {}
gen1.prototype.foo = "bar"
let gen2 = new gen1();
gen2.prop = "some prop"
console.log(`gen2.prop:${gen2.prop}`);
console.log(`gen2.foo :${gen2.foo}`);
console.log(`gen1.prop:${gen1.prop}`);
console.log(`gen1.foo :${gen1.foo}`);
console.log(`gen1.prototype.prop:${gen1.prototype.prop}`);
console.log(`gen1.prototype.foo:${gen1.prototype.foo}`);
//
gen2.prop:some prop
gen2.foo :bar
gen1.prop:undefined
gen1.foo :undefined
gen1.prototype.prop:undefined
gen1.prototype.foo:bar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 创建对象的几种方法及相关原型链

  1. 语法构造器

    //  直接构造的对象原型链o1 ---> Object.prototype ---> null
    let o1 = {
        a: 1
    }
    console.log(o1.__proto__ === Object.prototype); // true
    // 函数的原型为Function.prototype
    let f1 = function () {}
    console.log(f1.__proto__ === Function.prototype); // true
    // 数组的原型为Array.prototype,Array.prototype的原型为Object.prototype
    let a1 = ['1asdf', 'asdf']
    console.log(a1.__proto__ === Array.prototype); // true
    console.log(a1.__proto__.__proto__ === Object.prototype);// true
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
  2. 使用构造器:即new 后加函数

    function animal() {
        this.name = 'ani'
    }
    let cat = new animal();
    console.log(cat.__proto__ === animal.prototype); // true
    console.log(animal.prototype.__proto__ === Object.prototype); // true
    
    1
    2
    3
    4
    5
    6
  3. Object.create()

    let o = {
        name: 'ooo'
    }
    let o2 = Object.create(o)
    console.log(o2.__proto__ === o);// true
    
    1
    2
    3
    4
    5
  4. class关键词

    'use strict'
    class animal {
        constructor(age) {
            this.age = age;
        }
    }
    
    class cat extends animal {
        constructor(age, name) {
            super(age)
            this.name = name
        }
        get desc() {
            return this.name + ':' + this.age
        }
        set realName(catN) {
            this.name = catN
        }
    }
    let pet = new cat(12, 'kitty');
    console.log(pet.desc);// kitty:12
    pet.realName = 'mojo'
    console.log(pet.desc);// mojo:12
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

# 各种方式优劣势比较

优劣势比较 (opens new window)

# 关注Performance

  • 寻找属性时,在没找到前总是会沿着原型链往上找

  • 若整条链上没有这个属性,则总会走完完整的原型链

  • 若不想从原型链往上tranverse,可以调用obj.hasOwnProperty()

    let o = {
        name: 'ooo'
    }
    let o2 = Object.create(o)
    console.log(o2.__proto__ === o); // true
    console.log(o2.hasOwnProperty('name')); // false
    
    1
    2
    3
    4
    5
    6

参考: Mozilla (opens new window)

Last Updated: 1/22/2024, 8:56:53 AM