超详细JS原型链(建议收藏)

JS中的复杂类型基于对象,使用构造函数实现继承。ES6的class是语法糖,功能上可由ES5实现。每个函数有prototype属性,创建实例时,实例的__proto__指向构造函数的prototype,形成原型链。通过原型链,实例能访问构造函数原型对象上的方法,实现方法复用,减少内存开销。原型链的尽头是null。
摘要由CSDN通过智能技术生成

 JS原型

 JS的复杂类型都是对象类型的(Object),js是一种脚本语言,不是面向对象的。所以如何涉及继承机制是个问题。

JS中的构造函数

因为JS中没有类(Class)这个概念,所以JS的设计者使用了构造函数来实现继承机制。

 ES6中的class可以看作一个语法糖,它的绝大部分的功能,ES5都能做到。新的class写法只是让原型的写法更加的清晰、更像面向对象编程的语法而已

JS通过构造函数来生成实例:

// 构造函数
function Person(name,age){
    this.name = name;
    this.age = age;
}
// 创建实例
const lili = new Person('lili',18)

PS:在构造函数中通过this赋值的属性或者方法,是每个实例的实例属性以及实例方法,无法共享公共属性。所以又设计出了一个原型对象,来存储这个构造函数的公共属性以及方法。

补充知识:构造函数创建一个实例的过程

  1. 创建一个新对象
  2. 将构造函数的作用域赋值给新对象(这样this就指向了新对象)
  3. 执行构造函数中的代码(为新对象添加实例属性和实例方法)
  4. 返回新对象

什么是原型链?

原型链就是实例对象原型对象之间的链接。每个函数都有一个prototype属性,这个prototype属性就是我们的原型对象,我们拿这个函数通过new构造函数创建出来的实例对象,这个实例对象自己会有一个指针(_proto_)指向他的构造函数的原型对象!这样构造函数和实例对象之间就通过( _proto_ )连接在一起形成了链条。

原型对象:

JS的每个函数在创建的时候,都会生成一个属性prototype,这个属性指向一个对象,这个对象就是此函数的原型对象。该原型对象中有个属性为constructor,指向该函数。这样原型对象它的函数之间就产生了联系。

 JS原型链:

// 构造函数
function Person(name,age){
    this.name = name;
    this.age = age;
}

// 原型对象上的公共方法
Person.prototype.say =  function (word)  {
    // 模板字符串
    console.log(`${this.name}说:${word}`)
}

// 创建实例
const lili = new Person('lili',18);
// 返回布尔值,指对象自身属性中是否有指定属性
console.log("hasOwnProperty",lili.hasOwnProperty('say')) // false 说明不是定义再本身上的

lili.say('hello world') // 可以调用公共方法

 为什么我们构造的lili这个实例对象,它可以调用到Person这个构造函数原型对象上的方法呢?明明只有在构造函数内部通过this来赋值的属性或者方法才会被实例所继承,为什么在构造函数原型对象上定义的say方法也能通过实例来调用到呢?

JS有一个原型查找机制,把原来定义在实例上的方法,放到原型对象上去,通过构造函数的new操作,会把原型对象赋值给实例的__proto__属性,那么当使用返回的实例去调用某一个方法的时候,如果实例本身上没有,就去自动去实例的__proto__上去查找,这样达到方法的复用,减少内存开销。

prototype和proto:

prototype:显示原型,是构造函数的原型对象,函数的独有属性

proto:是实例对象指向原型对象的指针,隐式原型,是每一个对象都有的属性

每个通过构造函数创建出来的实例对象,其本身有个属性__proto__,这个属性会指向该实例对象构造函数原型对象,这么说好像有点绕,我们看下图:

 

__proto__ 并不是语言本身的特性,这是各大厂商具体实现时添加的私有属性,虽然目前很多现代浏览器的 JS 引擎中都提供了这个私有属性,但依旧不建议在生产中使用该属性,避免对环境产生依赖。生产环境中,我们可以使用 Object.getPrototypeOf 方法来获取实例对象的原型,然后再来为原型添加方法/属性。

注意点如果通过实例对象__proto__属性赋值,则会改变其构造函数原型对象,从而被所有实例所共享。

// 创建实例
const lili = new Person('lili',18);
// 返回布尔值,指对象自身属性中是否有指定属性
console.log("hasOwnProperty",lili.hasOwnProperty('say'))

lili.say('hello world')

// 通过__proto__属性赋值,会改变构造函数的原型对象,从而被所以实例所共享
lili.__proto__.do = function (){
    console.log('往原型对象中添加方法')
}

const zhangsan = new Person('zhangsan',20);
zhangsan.do(); // 打印了---往原型对象中添加属性

构造函数的prototype的__proto__指向哪里呢?(原型链的尽头)

我们发现了,对象的构造函数function Object,我们由此可以得知,所有的原型对象__proto__属性都是指向function Object原型对象function Object原型对象在上图中我们可以得知是不存在__proto__这个属性的,它指向了null。我们就得知了原型链的尽头是null

函数作为一个对象,是否存在原型链?

它的__proto__属性指向了一个function Function原型对象,该原型对象为JS中所有函数的原型对象,而其__proto__属性也还是指向了function Object原型对象。

 JS的原型链:(实例对象  函数  构造函数  函数函数 对象)

  • 10
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值