js对原型和原型链的理解

78 阅读1分钟

1. 原型

  1. 每个函数都有一个prototype(显式原型)
  2. 每个对象都有一个__proto__(隐式原型)
  3. 对象的__proto__全等于对应构造函数的prototype
// 定义构造函数
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    };
    sayMyself() {
        console.log(`我是${this.name}, 今年${this.age}岁`);
    };
};
// 1. 每个函数都有一个prototype(显式原型)
console.log('构造函数的prototype', Person.prototype);

const personFirst = new Person('温情', 23);
// 2. 每个实例对象都有一个__proto__(隐式原型)
console.log('实例对象的__proto__', personFirst.__proto__);

// 3. 对象的__proto__全等于对应构造函数的prototype
console.log(personFirst.__proto__ === Person.prototype);

原型.jpg

2. 原型链

当想访问一个对象的属性或方法时,有则返回,没有就通过__proto__去它的原型对象查找,原型对象找到则返回,找不到就继续通过原型对象的__proto__去查找,一层一层往上查找直到Object.prototype,有就返回,没有就是undefined,不会再往上查找了,因为Object__proto__null null的设计是为了避免死循环

// 父构造函数
class SecondLevel {
    constructor(name) {
        this.name = name;
    };
    study() {
        console.log('学习');
    };
}
// 继承 SecondLevel 属性与方法
class FirstLevel extends SecondLevel {
    constructor(name, age) {
        super(name);
        this.age = age;
    };
    playGame() {
        console.log('玩游戏');
    };
}
// 实例化对象
const exampleObj = new FirstLevel('温情', 20);

exampleObj.playGame();  // 输出 玩游戏

/* 因为 FirstLevel 通过 extends 继承了 SecondLevel 的属性和方法,通过原型链往上查找到了 SecondLevel 原型对象的 study 方法 */
exampleObj.study();  // 输出 学习

/* 可以看到FirstLevel和SecondLevel都没有定义toString方法,但是调用成功了,
这是因为跟着原型链向上查找,找到了顶层Object的prototype,Object的原型对象内置了toString方法 */
console.log(exampleObj.age.toString());  // '20'

// 再看看整个 exampleObj 的结构 结合 我画的图理解
console.log(exampleObj);

实例对象结构.jpg

原型链.png