总结:用于在现有对象的基础上构建新类型的对象。类似于类的语言中的 继承 。
对象实例上的原型可通过 Object.getPrototypeOf(object) 或 proto 属性获得,而构造函数上的原型可以通过 Object.prototype 获得。
虽然 Object.prototype 是原型链的 最顶层 ,但它本身也有一个原型对象 => null
。所以原型链的顶端实际上是 null 。总的来说,JavaScript 中的原型链 顶端是 null ,而原型链的最 顶层对象是 Object.prototype 。
function Fruit() {}
var fruit = new Fruit();
fruit.name = "Apple";
console.log(fruit.name); // Apple
Fruit 就是构造函数,fruit 是实例对象。对象通过 new 创建。
先看一段代码
function Fruit() {}
Fruit.prototype.name = "Apple";
const fruit1 = new Fruit();
const fruit2 = new Fruit();
console.log(fruit1.name); // Apple
console.log(fruit2.name); // Apple
每个 函数 都有一个 prototype 属性,函数的 prototype 属性指向了一个对象,这个对象正是调用该构造函数而创建的实例的原型,也就是这个例子中的 fruit1 的原型。
简单理解原型:每一个 JavaScript 对象 ( null 除外) 在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型”继承”属性。
我们已经知道,函数通过 prototype 和原型关联,那么实例对象是如何与原型关联的呢。
function Fruit() {}
var fruit = new Fruit();
console.log(fruit.__proto__ === Fruit.prototype); // true
从例子中可以发现 对象 是通过 __proto__
与原型关联。虽然大部分浏览器都支持通过 __proto__
访问原型,但是它并不存在于 Fruit.prototype 中。本质上是 Object.prototype 的 getter/setter。
每个原型都有一个 constructor 属性指向关联的构造函数。
function Fruit() {}
console.log(Fruit === Fruit.prototype.constructor); // true
读取实例属性的过程,实际是原型查找的过程。通过查找与对象关联的原型中的属性(如果查不到会继续往查找原型的原型,直到查到顶层 null )。
function Fruit() {}
Fruit.prototype.name = "Apple";
const fruit = new Fruit();
console.log(fruit.name); //1 Apple
fruit.name = "Banana";
console.log(fruit.name); //2 Banana
delete fruit.name;
console.log(fruit.name); //3 Apple
在 1 中给实例原型添加了 name = Apple 的属性,所以在实例化之后,fruit 中找不到 name 属性,就会从原型中 fruit.__proto__
也就是 Fruit.prototype
中查找。3 同理,删除对象中的 name 属性后会在原型查找。而在 2 中,由于给对象赋予了 name 属性,所以不需要查找原型即可得到 name。
其中被 __proto__
串起来的链状结构就是原型链。而原型链的顶层为 null(Object.prototype.__proto__ == null)。
从上面的例子来看,原型链大致呈:Fruit() —> fruit —__proto__
—> Fruit.prototype —__proto__
—> Object.prototype —__proto__
—> null
简单来讲,new 表达式是配合构造函数,通过 new 一个构造函数取继承属性。
__proto__
属性设置为构造函数的 prototype
属性。
__proto__
)属性被设置为构造函数的 prototype
属性。这一步确保了通过 new 创建的对象能够访问构造函数原型链上的属性和方法。 通过原型实现 new 操作
function Fruit(name) {
this.name = name;
}
function createInstance(Constructor, ...args) {
// 1&2. 创建空对象,并且 __proto__ 设置为 prototype
const obj = Object.create(Constructor.prototype);
// 3. 改变 this 指向
const result = Constructor.apply(obj, args);
// 4. 返回
return result instanceof Object ? result : obj;
}
const fruit = createInstance(Fruit, "Apple");
console.log(fruit.name); // Apple