一、前言
在面试过程中,频频被原型相关知识问住,每次回答都支支吾吾。后来有家非常心仪的公司,在二面时,果不其然,又问原型了!
我痛下决心用了两天时间钻研了下原型,弄明白后发现世界都明亮了,原来这么简单 ~
有些理解还比较浅薄,随着时间的推移和理解的深入,以后还会补充。如果大家发现我理解的有问题,欢迎大家在评论中指正。话不多说,切入正题。
二、构造函数
讲原型则离不开构造函数,让我们先来认识下构造函数。
2.1 构造函数分为 实例成员 和 静态成员
让我们先来看看他们分别是什么样子的。
实例成员: 实例成员就是在构造函数内部,通过this添加的成员。实例成员只能通过实例化的对象来访问。
静态成员: 在构造函数本身上添加的成员,只能通过构造函数来访问
function Star(name,age) {
//实例成员
this.name = name;
this.age = age;
}
//静态成员
Star.sex = '女';
let stars = new Star('小红',18);
console.log(stars); // Star {name: "小红", age: 18}
console.log(stars.sex); // undefined 实例无法访问sex属性
console.log(Star.name); //Star 通过构造函数无法直接访问实例成员
console.log(Star.sex); //女 通过构造函数可直接访问静态成员
2.2 通过构造函数创建对象
该过程也称作实例化
2.2.1 如何通过构造函数创建一个对象?
function Father(name) {
this.name = name;
}
let son = new Father('Lisa');
console.log(son); //Father {name: "Lisa"}
此时,son就是一个新对象。
2.2.2 new一个新对象的过程,发生了什么?
(1) 创建一个空对象 son {}
(2) 为 son 准备原型链连接 son.__proto__ = Father.prototype
(3) 重新绑定this,使构造函数的this指向新对象 Father.call(this)
(4) 为新对象属性赋值 son.name
(5) 返回this return this
,此时的新对象就拥有了构造函数的方法和属性了
2.2.3 每个实例的方法是共享的吗?
这要看我们如何定义该方法了,分为两种情况。
方法1:在构造函数上直接定义方法(不共享)
function Star() {
this.sing = function () {
console.log('我爱唱歌');
}
}
let stu1 = new Star();
let stu2 = new Star();
stu1.sing();//我爱唱歌
stu2.sing();//我爱唱歌
console.log(stu1.sing === stu2.sing);//false
很明显,stu1 和 stu2 指向的不是一个地方。
所以 在构造函数上通过this来添加方法的方式来生成实例,每次生成实例,都是新开辟一个内存空间存方法。这样会导致内存的极大浪费,从而影响性能。
方法2:通过原型添加方法(共享)
构造函数通过原型分配的函数,是所有对象共享的。
function Star(name) {
this.name = name;
}
Star.prototype.sing = function () {
console.log('我爱唱歌', this.name);
};
let stu1 = new Star('小红');
let stu2 = new Star('小蓝');
stu1.sing();//我爱唱歌 小红
stu2.sing();//我爱唱歌 小蓝
console.log(stu1.sing === stu2.sing);//true
2.2.4 实例的属性为基本类型是,它们是共享的吗?
属性存储的是如果存储的是基本类型,不存在共享问题,是否相同要看值内容。
let stu1 = new Star('小红');
let stu2 = new Star('小红');
console.log(stu1.name === stu2.name);//true
let stu1 = new Star('小红');
let stu2 = new Star('小蓝');
console.log(stu1.name === stu2.name);//false
2.2.5 定义构造函数的规则
公共属性定义到构造函数里面,公共方法我们放到原型对象身上。
更多面试题解答参见 前端进阶面试题详细解答
三、原型
前面我们在 实例化 和 实例共享方法 时,都提到了原型。那么现在聊聊这个神秘的原型到底是什么?
3.1 什么是原型?
Father.prototype 就是原型,它是一个对象,我们也称它为原型对象。
3.2 原型的作用是什么?
原型的作用,就是共享方法。
我们通过 Father