JavaScript 原型和原型链的理解

原型(Prototype)

在JavaScript中,每个对象(除了null)都有一个与之关联的原型对象(prototype),这个原型对象可以包含属性和方法,这些属性和方法会被该对象"继承"。

关键点:

  1. 每个函数都有一个prototype属性:当创建一个函数时,JavaScript会自动为该函数添加prototype属性。

    function Person() {}
    console.log(Person.prototype); // 输出一个对象
    
  2. 实例对象的__proto__属性:通过构造函数创建的实例对象会有一个__proto__属性,指向构造函数的prototype对象。

    const person = new Person();
    console.log(person.__proto__ === Person.prototype); // true
    
  3. 原型上的属性和方法可以被所有实例共享

    Person.prototype.sayHello = function() {
      console.log('Hello!');
    };
    
    const p1 = new Person();
    const p2 = new Person();
    
    p1.sayHello(); // Hello!
    p2.sayHello(); // Hello!
    

原型链(Prototype Chain)

原型链是JavaScript实现继承的机制。当访问一个对象的属性或方法时,如果该对象本身没有这个属性,JavaScript会沿着原型链向上查找,直到找到该属性或到达原型链的末端(null)。

原型链的构成:

  1. 实例对象 -> 构造函数的prototype -> Object.prototype -> null

    function Person() {}
    const person = new Person();
    
    // 原型链:
    // person -> Person.prototype -> Object.prototype -> null
    
  2. 更复杂的继承关系

    function Student() {}
    Student.prototype = new Person();
    
    const student = new Student();
    
    // 原型链:
    // student -> Student.prototype (Person实例) -> Person.prototype -> Object.prototype -> null
    

原型链查找示例:

function Person() {}
Person.prototype.name = 'Default';

const p1 = new Person();
console.log(p1.name); // 'Default' (从原型上找到)

p1.name = 'John';
console.log(p1.name); // 'John' (实例自身属性)

delete p1.name;
console.log(p1.name); // 'Default' (再次从原型上找到)

重要方法和属性

  1. Object.getPrototypeOf(obj):获取对象的原型(推荐替代__proto__
  2. obj.hasOwnProperty(prop):检查属性是否是对象自身的(非继承的)
  3. prop in obj:检查对象或其原型链上是否存在该属性
  4. instanceof:检查构造函数的prototype是否出现在对象的原型链上

实际应用

  1. 原型继承

    function Animal(name) {
      this.name = name;
    }
    
    Animal.prototype.speak = function() {
      console.log(`${this.name} makes a noise.`);
    };
    
    function Dog(name) {
      Animal.call(this, name); // 调用父类构造函数
    }
    
    // 设置原型链
    Dog.prototype = Object.create(Animal.prototype);
    Dog.prototype.constructor = Dog;
    
    Dog.prototype.speak = function() {
      console.log(`${this.name} barks.`);
    };
    
    const d = new Dog('Rex');
    d.speak(); // Rex barks.
    
  2. ES6类语法糖(底层仍然是基于原型):

    class Animal {
      constructor(name) {
        this.name = name;
      }
      
      speak() {
        console.log(`${this.name} makes a noise.`);
      }
    }
    
    class Dog extends Animal {
      speak() {
        console.log(`${this.name} barks.`);
      }
    }
    
    const d = new Dog('Rex');
    d.speak(); // Rex barks.
    

理解原型和原型链是掌握JavaScript面向对象编程的关键,也是理解JavaScript继承机制的基础。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • """1.个性化消息: 将用户的姓名存到一个变量中,并向该用户显示一条消息。显示的消息应非常简单,如“Hello ...
    她即我命阅读 8,550评论 0 5
  • 为了让我有一个更快速、更精彩、更辉煌的成长,我将开始这段刻骨铭心的自我蜕变之旅!从今天开始,我将每天坚持阅...
    李薇帆阅读 6,001评论 0 3
  • 似乎最近一直都在路上,每次出来走的时候感受都会很不一样。 1、感恩一直遇到好心人,很幸运。在路上总是...
    时间里的花Lily阅读 5,238评论 0 2
  • 1、expected an indented block 冒号后面是要写上一定的内容的(新手容易遗忘这一点); 缩...
    庵下桃花仙阅读 3,582评论 0 1
  • 一、工具箱(多种工具共用一个快捷键的可同时按【Shift】加此快捷键选取)矩形、椭圆选框工具 【M】移动工具 【V...
    墨雅丫阅读 3,561评论 0 0