翻阅到以前的学习笔记,加上自己现在的理解,谈一谈JS的原型链。
tips:本文有很多胡言乱语,如果你已经掌握js原型链,不建议阅读本文,以免被我误导。
对象的原型究竟在哪里?
function Person() {
}
let person = new Person();
复制代码
当初我很不理解,person的原型是什么? 很多教程就说:
person的原型是 person.__proto__
我又疑问,那Object的原型呢?
Object.__proto__
当初我真是特别崩溃。就好像,我问:老王的儿子是谁?有人回答:老王的儿子是老王.儿子
我期望的回答是类似于小李,小张的答案,而不是老王的儿子是老王.儿子
这种间接的答案。
对象继承
我们知道其他编程语言中的面对对象,往往都是基于类的面对对象。
就好像:有人类的概念,然后我们可以创建一个人类的实例。
基于类的面对对象的代码可能长这样子:
class Human{
}
new p1 = new Human()
复制代码
然后中国人的概念继承自人类
class Chinese extend Human{
}
let c1 = new Chinese()
复制代码
原型继承
JS和基于类的继承不同,JS是基于原型的。
但是在原型继承中,就没有人类,中国人类的概念了,取而代之的是一个人,一个中国人的概念。
汉语中,我们会说:李华是一个人。
一个人的概念和奇特。 你可以说小明是小明,小明是人类,但是不好说小明是“一个人” 就好像英文中,"a person" "the person" 的概念,当我们跟说道小明的时候,我们可能再说 "the person" 而不是 "a person",你找不到"a person" 因为你找到它的时候,他就是"the person"了。
JS中,除了四种基本类型,其他一切都是对象。在js中函数也被定义为对象。那是JS对象就要有原型,lihua
的原型是什么?你可能会这样做:
lihua.__proto__
,但其实不然,对象的原型是抽象的概念,他不存在于实体(js解释器的内存中)。
lihua
是什么? lihua
是 一个人
,一个人
具有的特征李华都应该有。地球上有许多人,但是并不存在一个人
这样的实体。
有人可能会说:"我不是在控制台打印了lihua.__proto__
吗,那么在js解释器的内存中,lihua
的 __proto__
指向的内存不就是一个人
吗?"
其实这是一种误解,lihua
并没有一个叫__proto__
的属性。
lihua
的原型的特征是什么,但是不能说
lihua
的原型在某块JS内存区。
一个
在我个人理解中,用一个
的概念更容易理解JS的原型链.Object.prototype
可以理解为一个对象。Function.prototype
可以理解为一个函数,然后一个函数的原型就是一个对象,所以 Function.prototype.__proto__ === Object.prototype
下面是我画的原型链的图
obj
就是Object.prototype
、一个对象
;fun
就是Function.prototype
、一个函数
;以此类推。
我们来捋一捋原型链。lihua
原型是一个人
,一个人
的原型是一个对象
。 Array
是一个函数
,所以他的原型是一个函数
,同时他又是Functin
的实例。一个Array的实例又是一个数组
,一个数组
的原型又是一个对象
。
用一个
的概念来理解原型,是不是容易很多?
Object.create()
我们知道,除了通过构造函数,我们还可以通过Object.create()来创建一个对象。
let a = {}
let b = Object.create(a)
复制代码
这段代码的意思就是创建一个对象b,并将b的原型指定为a。
这是有人可能会说:我这不是找到b的原型了吗?
b.__proto__ === a //true
其实我是这样想的:
let obj = {
name:"lihua"
}
let str = JSON.stringfiy(obj)
复制代码
如果把obj,str理解为JSON数据,他们表达的信息没有任何区别。
上述代码中,a既是JS解释器内存中的对象,又能表达b的原型有怎样的特征。 语法上b.__proto__ === a //true
,但是逻辑上b的原型是抽象的概念,a只是b的原型的一种表达。
比如下面三段代码
function hi(){
console.log("hi")
}
let h1 = new hi()
let lihua = {
name:"lihua"
}
let l1 = Object.create(lihua)
let aperson = {
eat:()=>{
console.log(this.name + " is eatting")
}
}
let lihuai = Object.create(aperson)
复制代码
第一段代码和第二段代码没有任何语法错误,但是逻辑上没人会这么写,因为h1
,l1
没有任何逻辑上的意义。
第三段代码和第二段没有什么语法上的区别,但是他有逻辑意义。我们创建了一个对象lihua
,lihua
的原型是一个人,而一个人有eat
这个固有特征,大家都知道这是什么意义。等价于下面的代码:
function Person(){}
Person.prototype.eat = ()=>{
console.log(this.name + " is eatting")
}
复制代码
结语
说了半天,就是想表达:不要单纯从语法上理解JS的原型链,还要考虑其中的逻辑意义。对象和对象的原型之间的关系就想李华和一个人之间的关系。