【Javascript】还不懂原型和原型链吗?

174 阅读3分钟

老生常谈的问题:原型是什么

几乎每个JavaScript对象都有另一个与之关联的对象

这另一个对象被称为原型(prototype) ,第一个对象从这个原型继承属性。image-20221110094359494

1.通过对象字面量创建的所有对象都有相同的原型对象使用Object.prototype作为其原型

对象和数组初始化程序也是一种表达式,其值为新创建的对象或数组。这些初始化程序表达式有时候也被称为对象字面量数组字面量

let hsiao =[1,2,3] //数组初始化程序
let hsiao2 = {x:2 , y:3} //对象初始化程序

我们可以通过控制台调试,发现有这个[[Prototype]],而他的值

image-20221110094513547

Object.prototype,就是同一个东西

image-20221110104207256

2.使用new关键字构造函数调用创建的对象,使用构造函数prototype属性的值作为它们的原型。

换句话说,使用new Object()创建的对象继承自Object.prototype,与通过{}创建的对象一样。

image-20221110104424433

类似地,通过new Array()创建的对象以Array.prototype为原型,通过new Date()创建的对象以Date.prototype为原型。

image-20221110104527624

引出原型链

对于我这种JavaScript初学者,这一块很容易迷惑。

几乎所有对象都有原型,但只有少数对象有prototype属性。正是这些有prototype属性的对象为所有其他对象定义了原型。

(用人话来说:这些少数对象作为小bossprototype拿来共享给别的对象用)

Object.prototype是为数不多的没有原型的对象,因为它不继承任何属性。

(用人话来说:它是最大BOSS

很好理解吖:其他的原型对象都是都是常规对象,由它而来的,所以才有自己的原型Object.prototype

//比如我简单创建一个a空数组
let hsiao =new Array()
console.log(hsiao)
​
//控制台得到的结果
[]
//打开数组
length:0
[[prototype:Array(0)]]
//打开[[prototype:Array(0)]]
at: ƒ at()
concat: ƒ concat()
...
[[Prototype]]: Object
//打开 [[Prototype]]: Object
...
//没有出现下一个[[Prototype]]

代码没法全部展现这个 “链子” ,画个图更直观一点

image-20221110112640037

多数内置构造函数(和多数用户定义的构造函数)的原型都继承自Object.prototype。例如,Date.prototypeObject.prototype继承属性,因此通过new Date()创建的日期对象从Date.prototypeObject.prototype继承属性。

这种原型对象链接起来的序列 (套娃) 被称为原型链

浅尝原型链

  • instanceof操作符:期待左侧操作数是对象,右侧操作数是对象类的标识。这个操作符在左侧对象是右侧类的实例时求值为true,否则求值为false。所以我们可以利用这个特性来加深一下对原型链的理解。

    let hsiao = new Date() //用D构造函数创建一个新对象  
    hsiao instanceof Date //true
    hsiao instanceof Object //true
    hsiao instanceof Math //false
    

    如果instanceof的左侧操作数不是对象,它会返回false。如果右侧操作数不是对象的类,它会抛出TypeError

  • 要确定一个对象是不是另一个对象的原型(或原型链中的一环),可以使用isPrototypeOf()方法:

    let p = {x:1}//定义一个原型对象
    let o = Object.create(p) //用该原型创建一个对象
    p.isPrototypeOf(o) //true o继承p
    Object.prototype.isPrototypeOf(p) //true p继承Object.prototype
    Object.prototype.isPrototypeOf(o) //true o继承Object.prototype
    

总结

原型和原型链没有想象中那么简单,但也不会很复杂。

重要是理清楚其中的prototype,[[prototype]],__proto__之间到底有什么关系,举个最简单的例子:

  1. 对象test 的构造函数Test有个自己的属性prototype
  2. 对象test 本身有个属性__proto__ 或者叫 [[prototype]]
  3. 两者相同

利用这层关系将上一级的属性归下一级的对象所用,这才能发挥原型链的作用。