原型
1. prototype
// 首先我们创建一个构造函数
function human(){
}
// 实例化
let liLei = new human();
console.log(liLei);
- 我们可以看到,函数都有一个 prototype 属性,我们称之为函数的原型
那么prototype属性有什么用呢?
// 创建一个构造函数
function human(){
}
// 在prototype上加上一条属性name为lilei
human.prototype.name = 'lilei';
// 实例化
let liLei = new human();
let hanMei = new human();
console.log(liLei);
console.log(hanMei);
- 在上述代码中,我们在函数的原型中加入了新的属性并为其赋值,之后实例化函数,发现:JavaScript对象(null除外)在创建的时候就会关联另一个对象,这个对象就是我们所说的原型(prototype),每一个对象都会从原型"继承"属性。
那么,是什么属性导致实例化的函数与函数的原型之间可以像“项链”一样连接在一起呢?
2. __proto__
function human(){
}
human.prototype.name = 'lilei';
let liLei = new human();
console.log('liLei.__proto__ === human.prototype');
console.log(liLei.__proto__ === human.prototype);
console.log('-------------------------------');
console.log('liLei.__proto__');
console.log(liLei.__proto__);
console.log('-------------------------------');
console.log('human.prototype');
console.log(human.prototype);
- 由上述代码可看出,每个实例化的对象都拥有一条链子(__proto__)与构造函数的原型(prototype)同时指向调用该构造函数而创建的实例的原型,我们称其为隐式原型。
关系图如下
我们知道构造函数可以生成多个实例,那么函数原型是如何找到构造函数的呢?
3. constructor
function human(){
}
human.prototype.name = 'lilei';
let liLei = new human();
console.log(human.prototype);
- 由上图我们可知,函数原型通过constructor来找到构造函数。
原型链
在了解到原型链之前,先提出一个问题
function human(){
}
human.prototype.name = 'Whatever';
let zhangSan = new human();
zhangSan.name = 'zhangsan';
console.log('zhangSan.name');
console.log(zhangSan.name);
console.log('-------------------------------');
delete zhangSan.name;
console.log('delete zhangSan.name');
console.log(zhangSan.name);
在上述代码中,首先在函数原型中加入name属性为Whatever,之后在实例化函数中加入同名属性赋值为zhangsan,如果删除实例化中的name属性,其name输出的值是什么呢?
- 由上述结果可知,当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性。
如果在对象关联的原型中也没有找到这个属性呢?
不得不请出对象的根Object函数
function human(){
}
let obj = new Object();
let zhangSan = new human();
obj.__proto__.name = 'root';
console,log('zhangSan.name')
console.log(zhangSan.name);
- 我们首先创建了Object的实例,在它的原型上新增了属性name,然后我们在zhangSan的实例对象上并没有新增任何属性,输出其name的值时,发现结果为Object原型对象的值。
- 由此我们总结可以得出:当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层(Object的原型)为止。
那么Object原型的原型是什么呢?
我们试一下
let obj = new Object();
obj.__proto__.name = 'root';
console.log('obj.__proto__.__proto__');
console.log(obj.__proto__.__proto__);
- 结果为null
我们可以总结一张完整的原型关系图
- 图中由相互关联的原型组成的链状结构就是原型链,也就是蓝色的这条线。