学习笔记-JavaScript的原型和原型链

基本概念

1. 原型(Prototype)

在JavaScript中,每个函数都有一个特殊的属性叫做prototype(原型属性),这个属性指向一个对象,该对象包含了可以由该函数创建的所有实例共享的属性和方法。

js 复制代码
function Person(name) {
    this.name = name;
}

// 为Person的原型添加方法
Person.prototype.sayHello = function() {
    console.log(`Hello, I'm ${this.name}`);
};

const person1 = new Person('Alice');
person1.sayHello(); // "Hello, I'm Alice"

2. 原型链(Prototype Chain)

当访问一个对象的属性时,JavaScript引擎会:

  1. 首先在该对象自身属性中查找
  2. 如果没有找到,则沿着原型链向上查找
  3. 直到找到该属性或到达原型链的末端(null)

核心机制

1. __proto__ 属性

每个对象都有一个__proto__属性,指向创建该对象的构造函数的prototype

js 复制代码
function Animal(type) {
    this.type = type;
}

const dog = new Animal('mammal');

console.log(dog.__proto__ === Animal.prototype); // true
console.log(Animal.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null

2. 构造函数、原型、实例的关系

rust 复制代码
实例对象 --__proto__--> 构造函数的prototype --constructor--> 构造函数

深入理解

1. 原型继承

js 复制代码
// 父类
function Animal(name) {
    this.name = name;
}

Animal.prototype.eat = function() {
    console.log(`${this.name} is eating`);
};

// 子类
function Dog(name, breed) {
    Animal.call(this, name); // 调用父类构造函数
    this.breed = breed;
}

// 设置原型链继承
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

// 添加子类特有方法
Dog.prototype.bark = function() {
    console.log(`${this.name} is barking`);
};

const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.eat();  // 继承自Animal
myDog.bark(); // Dog自己的方法

2. ES6 Class语法糖

js 复制代码
class Animal {
    constructor(name) {
        this.name = name;
    }
    
    eat() {
        console.log(`${this.name} is eating`);
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name);
        this.breed = breed;
    }
    
    bark() {
        console.log(`${this.name} is barking`);
    }
}

// 本质上还是基于原型的继承
console.log(typeof Animal); // "function"
console.log(Animal.prototype.hasOwnProperty('eat')); // true

重要方法和属性

1. 原型相关方法

js 复制代码
function Car(brand) {
    this.brand = brand;
}

Car.prototype.drive = function() {
    console.log(`${this.brand} is driving`);
};

const myCar = new Car('Toyota');

// 检查原型关系
console.log(myCar instanceof Car); // true
console.log(Car.prototype.isPrototypeOf(myCar)); // true

// 检查属性来源
console.log(myCar.hasOwnProperty('brand')); // true
console.log(myCar.hasOwnProperty('drive')); // false

// 获取原型
console.log(Object.getPrototypeOf(myCar) === Car.prototype); // true

2. 属性遍历

js 复制代码
function List(items) {
    this.items = items || [];
}

List.prototype.add = function(item) {
    this.items.push(item);
};

const myList = new List([1, 2, 3]);
myList.customProp = 'custom';

// for...in 会遍历原型链上的可枚举属性
for (let key in myList) {
    console.log(key); // items, customProp, add
}

// Object.keys 只返回自身可枚举属性
console.log(Object.keys(myList)); // ['items', 'customProp']

// 获取所有自身属性(包括不可枚举)
console.log(Object.getOwnPropertyNames(myList)); // ['items', 'customProp']

实际应用场景

1. 方法共享与内存优化

js 复制代码
// 不好的做法:每个实例都创建新函数
function BadCircle(radius) {
    this.radius = radius;
    this.getArea = function() {
        return Math.PI * this.radius * this.radius;
    };
}

// 好的做法:方法放在原型上共享
function GoodCircle(radius) {
    this.radius = radius;
}

GoodCircle.prototype.getArea = function() {
    return Math.PI * this.radius * this.radius;
};

const circles = [];
for (let i = 0; i < 1000; i++) {
    circles.push(new GoodCircle(i));
}
// 所有实例共享同一个getArea方法,节省内存

2. 扩展内置对象

js 复制代码
// 为数组添加自定义方法(谨慎使用)
Array.prototype.last = function() {
    return this[this.length - 1];
};

const arr = [1, 2, 3, 4, 5];
console.log(arr.last()); // 5

原型链示意图

javascript 复制代码
实例对象
    ↓ __proto__
构造函数的prototype
    ↓ __proto__
Object.prototype
    ↓ __proto__
null

总结要点

  1. 每个函数都有prototype属性‌,指向原型对象
  2. 每个对象都有__proto__属性‌,指向创建它的构造函数的prototype
  3. 原型链的终点是null
  4. 原型继承是JavaScript的核心继承机制
  5. ES6的class语法本质上是原型继承的语法糖
相关推荐
好奇的候选人面向对象3 小时前
基于 Element Plus 的 TableColumnGroup 组件使用说明
开发语言·前端·javascript
小纯洁w3 小时前
vue3.0 使用el-tree节点添加自定义图标造成加载缓慢的多种解决办法
前端·javascript·vue.js
老前端的功夫3 小时前
ES6 模块 vs CommonJS:从历史背景到引擎实现的深度解析
前端·javascript
colorFocus3 小时前
大数据量计算时的延迟统一处理
前端·javascript
San303 小时前
在浏览器中运行AI模型:用Brain.js实现前端智能分类
前端·javascript·机器学习
小高0073 小时前
从npm run build到线上部署:前端人必会的CI/CD套路
前端·javascript·面试
古一|3 小时前
ES6(ECMAScript 2015)完全指南:从基础特性到异步解决方案(附实战)
javascript·es6
Every exam must be4 小时前
10.27 JS学习12
开发语言·javascript·学习
程序0074 小时前
微信小程序app.js错误:require is not defined
javascript·微信小程序·小程序