一、原型介绍
JavaScript中没有"类"的概念,它通过原型prototype来实现对象间的属性和方法共享。既能节省内存,又能实现继承关系。
性质
-
共享性:所有实例共享原型上的属性和方法
-
动态性:可以随时修改原型,所有实例会立即受到影响
-
链式查找:当访问对象属性时,会沿着原型链向上查找
使用:
javascript
//为数组拓展方法
const arr=new Array(3,4,5)
Array.prototype.max=function(){
//利用环境对象this(谁引用指向谁)和展开运算符
return Math.max(...this)
}
arr.max()->5
//输出5
//求和函数
Array.prototype.sum=function(){
return this.reduce((prev,current)=>prev+current)
}
arr.sum()->12
将方法写在prototype上,实例就可以使用这些方法
二、constructor属性
每个函数在创建时,都会自动获得一个prototype属性,这个prototype对象会自动获得一个constructor属性,指回函数本身 。
constructor是原型对象上的一个重要属性,它建立了构造函数与原型对象之间的双向联系。
javascript
function Person(name) {
this.name = name
}
// 自动建立的关联
console.log(Person.prototype.constructor === Person) // true
constructor的重写问题:
javascript
function Hello(){}
// 重写原型对象
Hello.prototype = {
happy: function(){},
sad: function(){}
}
// 此时constructor指向Object,而非Hello
// 正确的重写方式
Hello.prototype = {
constructor: Hello, // 手动恢复constructor引用
happy: function(){},
sad: function(){}
}
关键点:
- 直接赋值对象字面量会覆盖默认的prototype对象
- 重写后必须显式设置constructor以保证原型链完整
- 可以使用Object.defineProperty设置不可枚举的constructor属性
三、对象原型(proto)
当我们用new创建实例时,实例会链接到构造函数的prototype:
javascript
const person1 = new Person('小明')
console.log(person1.__proto__ === Person.prototype) // 等价
使得实例能访问原型上的属性和方法。
__proto__用来表明当前实例对象指向哪个原型对象prototype,里面也有一个constructor属性,指向创建该实例对象的构造函数。
四、原型继承
JavaScript的继承是通过原型链实现的:
javascript
function Student(grade) {
this.grade = grade
}
// 让Student的原型指向Person的实例
Student.prototype = new Person()
const student1 = new Student(3)
console.log(student1.name) // undefined (但能通过原型链找到name属性)
console.log(student1.__proto__.__proto__ === Person.prototype) // true
示意:
student1
↓ __proto__
Student.prototype
↓ __proto__
Person.prototype
↓ __proto__
Object.prototype
↓ __proto__
null
关键细节:
-
必须修复constructor指向
-
子类构造函数中需要调用父类构造函数(借用构造函数模式)
-
形成完整的原型链结构
五、完整关系图谱
- 构造函数:
-
通过prototype属性指向其原型对象
-
用于创建实例对象
- 原型对象:
-
包含共享的属性和方法
-
通过constructor属性指回构造函数
-
自身的__proto__指向上一级原型Object.prototype
3.实例对象:
-
通过__proto__指向构造函数的原型对象
-
可以访问原型链上的所有属性和方法
补充说明:
所有原型链最终都指向Object.prototype
Object.prototype.__proto__为null
使用instanceof运算符可以检测原型链关系