1. 原型(Prototype)
每一个 JavaScript 对象( null 除外)在创建时会与之关联另一个对象,这个被关联的对象称之为 原型(原型对象)。每一个对象都会从原型中‘继承’(委托)原型对象的属性。原型对象就是用来存放实例中共有的那部分属性。每个函数都有一个特殊的属性叫作原型(prototype),这个属性指向调用该构造函数而创建的实例的原型。原型对象中有一个属性 constructor, 它指向函数对象。
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log('Hello, ' + this.name + '!');
};
const person1 = new Person('Kimi');
const person2 = new Person('Alice');
person1.greet(); // 输出: Hello, Kimi!
person2.greet(); // 输出: Hello, Alice!
在这个例子中,Person.prototype
是person1
和person2
的原型。它们共享greet
方法,但有自己的name
属性。
什么是 prototype
prototype 是函数才有的属性,这个属性指向一个对象,该对象正是调用该构造函数而创建的实例的原型。指向原型对象。箭头函数是没有 prototype 属性的。在最新 ES 规范里,prototype 被定义为:给其它对象提供共享属性的对象。每个函数都有一个 prototype 属性,它默认指向一个 Object 空对象(即称为:原型对象)。
注意
并不是所有的函数都有 prototype 属性,由函数 bind()方法返回的函数就没有 prototype 属性。
函数的 prototype 属性,在定义函数时自动添加 prototype,默认是一个空 Object 对象
什么是 __proto__
隐式原型
每一个 JavaScript 对象( null 除外)都有一个属性,叫 __proto__
,这个属性指向该对象的原型。指向原型对象, 原型对象其实就是通过 Object 构造函数生成的。它是历史遗留,在某些环境中,比如 Deno,它是不被支持的。所有函数的 __proto__
指向他们的原型对象。
什么是 constructor
每个原型都有一个 constructor 属性指向关联的构造函数。
constructor 属性其实就是一个拿来保存自己构造函数引用的属性,没有其他特殊的地方。默认 constructor 实际上是被当做共享属性放在它们的原型对象中。
2. 原型链(Prototype Chain)
一个实例对象在调用属性和方法的时候,会依次从实例本身、构造函数原型、原型的原型上去查找
原型链是一个用于属性查找的对象链表。当访问一个对象的属性时,如果该对象本身没有这个属性,JavaScript引擎会沿着原型链向上查找,直到找到该属性或到达链的末端。
原型链的起点是对象的内部属性[[Prototype]]
(通常通过Object.getPrototypeOf()
或__proto__
属性访问),终点是null
,因为Object.prototype
的原型是null
。
const obj = {
a: 1
};
const protoObj = Object.create(obj);
protoObj.b = 2;
console.log(protoObj.a); // 输出: 1,因为protoObj的原型上有a属性
console.log(protoObj.b); // 输出: 2,因为protoObj上有b属性
在这个例子中,protoObj
的原型是obj
,所以当访问protoObj.a
时,会沿着原型链找到obj
上的a
属性。
通过原型链的继承,一个对象可以访问其父对象或更高级别原型链上的属性和方法:
class User {
constructor(username, password) {
this.username = username;
this.password = password;
}
login() {
console.log("登录");
}
}
function Admin() {
this.deletePerson = function() {
console.log("删除");
};
}
Admin.prototype = new User();
let admin = new Admin();
admin.login(); // 输出:登录
在这个例子中,Admin 对象没有 login 方法,但它通过原型链从 User 对象继承了这个方法。