前置知识
对初学者来说一般很难理解原型和原型链的概念,但是原型和原型链又是 JS 中组中非常重要的知识点之一
- 想要弄清楚原型和原型链,需要清楚:__ proto__ 、prototype、constructor
- JS 中对象和函数之间的关系:函数是对象的一种
- 函数、构造函数之间的区别:任何函数都可以作为构造函数,只有通过 new 关键字调用才可以把函数称为构造函数。
// 定义一个普通函数 Person
function Person() {
this.name = name
}
// 通过 new 关键字调用 Person 函数 创造了 p 实例
// 此时 Person 是一个构造函数
var p = new Person()
原型、原型链
原型 —— prototype
- 原型 prortotype 是构造函数的属性
- prototype 本身是一个对象
- prototype 是一个存储空间,存储的信息其后代都可以使用
- 最终指向 空
原型链 __ proto__
- 实例化构造函数的结果,属于实例对象(函数)独有的属性
- 是一个容器,存储构造函数的 prototype
- 是一个隐式属性,系统隐式添加到实例对象上
构造函数 —— constructor
- 对象才有的属性
- 一定是一个函数
以上三张关系图,反复多看几次、理解一下可以清楚明白其三者之间的关系
原型、原型链案例分析
原型
- 原型上的属性,其后代都可以访问
function Car() {
this.color = "red";
this.brand = "奔驰";
}
Car.prototype.source= 'Europe' // 设置 Car 函数对象的原型
var car1 = new Car();
console.log(Car) // {source: 'Europe', constructor: f Car()}
console.log(car1); // {brand: "奔驰", color: "red"}
console.log(car1.source) // Europe,原型上的属性,其后代都可以访问并使用
原型链
- __ proto__ 是可以修改的,修改后的值直接覆盖之前的值
function Car(){
this.__proto__ = Car.prototype //实例化之后 隐式的给this 添加一个 __proto__属性
}
Car.prototype.name = 'Bena'
var car = new Car()
console.log(car)
function Car() {}
Car.prototype.name = "";
var car1 = new Car();
Car.prototype.name = 'Benz' // 修改 prototype.name 属性
Car.prototype = { // 重写 prototype 属性
name: "Mazda"
}
// 重写 prototype 属性 修改了实例化对象中 this.__proto__ 容器中包含的prototype 的值
console.log(car1.name); // Benz
// 以 Car.prototype.name = 'xxx' 的方式会直接修改 Car.prototype.name 的属性值
// car1 实例化于重写 Car.prototype 属性之前 ,因此他当前的 name 指向 Benz
// car1.__proto__ --> Car.prototype ,因此访问的是修改前的 Car.prototype.name
console.log(Car.prototype.name); // Mazda
// 重写 Car.prototype.name 修改之后 就会去覆盖之前的属性值
原型、原型链 是一个比较抽象的知识点,在工作中也不常用,因此需要反复的巩固,个人也会出现长时间不看,混乱的情况。