发如飞絮——Javascript原型到原型链

123 阅读2分钟

原型

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

我们可以总结一张完整的原型关系图

  • 图中由相互关联的原型组成的链状结构就是原型链,也就是蓝色的这条线。