对象原型 (Prototypes)
JavaScript 对象原型
Section titled “JavaScript 对象原型”每个 JavaScript 对象都链接到另一个称为其“原型”(prototype) 的对象。这个原型对象也有自己的原型,以此类推,形成一个“原型链”(prototype chain)。
当你尝试访问对象的属性或方法时,JavaScript 会首先在该对象自身查找。如果找不到,它会在其原型上查找,然后是原型的原型,以此类推,直到找到属性或链条以 null 结束。
这种机制被称为“原型继承”(prototypal inheritance),它是 JavaScript 对象如何继承特性的基础。
使用对象字面量 ({}) 或 new Object() 创建的对象继承自 Object.prototype。
使用“构造函数”(constructor function) 创建的对象(例如,new Date())继承自构造函数的 prototype 属性(例如,Date.prototype)。
Object.prototype 位于大多数对象的原型链顶端。它提供了诸如 toString()、hasOwnProperty() 等常见方法。
使用构造函数创建对象
Section titled “使用构造函数创建对象”创建共享同一原型的对象的常用方法是使用构造函数:
// 用于创建 Person 对象的构造函数function Person(first, last, age, eyeColor) { this.firstName = first; this.lastName = last; this.age = age; this.eyeColor = eyeColor;}
// 给 Person 原型添加一个方法Person.prototype.getFullName = function() { return `${this.firstName} ${this.lastName}`;};使用构造函数时,你需要使用 new 关键词来创建新的对象(即“实例”(instance))。这些实例将继承自 Person.prototype。
const myFather = new Person("John", "Doe", 50, "blue");const myMother = new Person("Sally", "Rally", 48, "green");
console.log(myFather.getFullName()); // 输出:John Doeconsole.log(myMother.getFullName()); // 输出:Sally Rally添加到构造函数的 prototype 属性上的方法会由所有实例共享,这使其更加节省内存。 |
|---|
ES6 类:语法糖
Section titled “ES6 类:语法糖”ES6 引入了 class 语法,它提供了一种更清晰、更熟悉的方式(对于来自基于类的语言的开发者而言)来创建对象和管理继承。本质上,JavaScript 的类仍然使用原型继承。
这是使用 class 语法的 Person 示例:
class Person { constructor(first, last, age, eyeColor) { this.firstName = first; this.lastName = last; this.age = age; this.eyeColor = eyeColor; }
getFullName() { return `${this.firstName} ${this.lastName}`; }
// 静态属性(属于类,不属于实例) static species = "Homo sapiens";}
const myFriend = new Person("Alex", "Smith", 30, "brown");console.log(myFriend.getFullName()); // 输出:Alex Smithconsole.log(Person.species); // 输出:Homo sapiens为单个对象添加属性/方法
Section titled “为单个对象添加属性/方法”你可以直接为单个对象实例添加属性或方法。这些属性或方法仅存在于该特定对象上。
myFather.nationality = "English"; // 只添加到 myFather 对象上的属性console.log(myFather.nationality); // 输出:English// console.log(myMother.nationality); // 输出:undefined
myMother.greet = function() { // 只添加到 myMother 对象上的方法 return `Hello, I am ${this.getFullName()}`;};console.log(myMother.greet()); // 输出:Hello, I am Sally Rally// myFather.greet(); // 这将导致错误修改原型(请谨慎使用)
Section titled “修改原型(请谨慎使用)”你可以向现有构造函数的 prototype 属性添加新的属性和方法。这将使它们对该构造函数的所有现有和将来的实例都可用(除非某个实例具有同名属性)。
// 通过原型给所有 Person 实例添加新方法Person.prototype.getAgeInYears = function() { return `${this.age} years old`;};
console.log(myFather.getAgeInYears()); // 输出:50 years oldconsole.log(myMother.getAgeInYears()); // 输出:48 years old**重要提示:**仅修改你自己定义的原型。切勿修改标准内置 JavaScript 对象的原型,如 Object.prototype、Array.prototype 等。这被认为是糟糕的做法,因为它可能导致不可预测的行为,并与其他代码或未来的 JavaScript 版本冲突。 |
|---|