JS原型链详解

例子:

js 复制代码
function Person(name,walk){
    this.name=name
    this.walk=walk
    this.getName=function(){
        console.log(this.name)
    }
}
Person.eat=function(){console.log('eat')}
Person.prototype.getWalk=function(){console.log(this.walk)}
const person=new Person('张三','顺拐')

constructor

  1. 当我们找实例的constructor的时候他自己本身是没有的,所以会沿着原型链往上找,而他原型链的上一级是他构造函数的prototype,这个有constructor,所以会被实例继承,而这个constructor指向构造函数本身,即person无constructor,他继承Person.prototype的constructor,而Person.prototype.constructor=Person,所以person.construtor=Person

  2. 构造函数本身也是一个对象,他作为对象的行为和实例也一样,即Person作为对象的行为和person是一样的,所以他也会继承他的构造函数的prototype的constructor,而所有的函数作为对象时的构造函数均是Function,所以Person.constructor=Function.prototype.constructor=Function

prototype(原型对象)与__proto__(对象原型,下面简称原型)

  1. 函数有一个对象属性是prototype(只有函数有,普通对象是没有的),注意箭头函数没有prototype ,构造函数也是函数所以也有prototype,这个属性定义了构造函数制造出来的对象的公共祖先,通过该构造函数产生的对象可以继承该原型的属性和函数,即person可以继承Person.prototype上的函数

  2. 实例的原型 都指向他的构造函数的原型对象,即person的原型指向Person.prototype

  3. 所有的函数(包括箭头函数,箭头函数只是没有prototype而已,也就是不能构造实例)的构造函数都是Function,即所有的函数都是Function的实例,包括Object,因为Object本身也是构造函数,可以拿来构造对象,所以任何函数的原型 都指向Function.prototype,所以Object的原型 也指向Function.prototype,而Function是一个构造函数,所以Function自己也是由Function.prototype构造的,即Function本身的原型也指向Function.prototype

  4. 普通对象是Object的实例,即由Object构造的所以Object是普通对象的构造函数,所以普通对象的原型为Object,注意,构造函数是函数,但是构造函数的prototype本身是一个非函数对象,即Person.prototype和Function.prototype的原型都指向Object.prototype

    而Object.prototype理论上来说也是对象那也应该由Object.prototype构造,但是为了避免循环所以Object.prototype指向null

  5. 参考3,4可知原型链即对象的原型,原型的原型...,比如person的原型链为person=>Person.prototype=>Object.prototype=>null ,并且要理解Person的原型链是Person=>Function.prototype=>Object.prototype=>null ,Function的原型链是Function=>Function.prototype=>Object.prototype

  6. 注意,在构造函数中写this.属性那构造函数不会有这个属性,因为这本质上是一条语句而不是属性,this是指向调用方的,所以实例中会有这个属性,比如

    js 复制代码
    function Person(){
        this.name=15
    }
    const p=new Person()
    console.log(p.name)//15
    console.log(Person.name)//undefined
    Person.prototype.name=20
    console.log(p.name)//15,因为原型链从底往上找的

    一般像这种固定值的属性没必要放在Person中用this给实例定义,因为这样一来每个实例都会创建一个,不如直接放在原型上即Person.prototype.name=15这样如何Person里不再定义this.name

  7. 如果修改Person.prototype的引用即Person.prototype={}有两种情况,若实例是在修改前定义的那实例将无法连接到新的Person.prototype上,因为他已经连接到旧的上了,如果在修改后定义那就连接在新的上面,注意Person能否连接到新的上面取决于新的引用是否将constructor指回Person,永远记得Person.prototype也只是一个对象,他和Person的连接是通过上面的constructor对象属性指向Person完成的,新对象如果直接没定义constructor或者定义成别的那也连接不上Person

  8. 通过实例是无法修改构造函数原型上的属性的,比如如果person.name='李四'那这个是给perosn实例这个对象上添加了一个叫name的属性而不是Person.prototype.name被修改了; delete person.name只能删除person自己的name属性不会删除Person.prototype的name属性,但是注意即使person上没name这个也会返回true,这不代表Person.prototype的name属性被删除了,而是执行删除没找到要删除的也算删除成功 ;

相关推荐
To_OC11 小时前
LC 51 N 皇后:我以为难的是回溯,结果栽在了对角线下标
javascript·算法·leetcode
Scott9999HH11 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社12 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海12 小时前
python 列表、元组、集合和字典
开发语言·python
小林ixn13 小时前
从零到一理解 React 父子组件通信:手写一个 Todo 应用带你彻底搞懂单向数据流
前端·javascript·react.js
萧瑟余晖13 小时前
JDK 26 新特性详解
java·开发语言
马优晨14 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
窝子面15 小时前
手搓最简前后端协作-node
javascript·数据库
人邮异步社区16 小时前
怎么把C语言学到精通?
c语言·开发语言
kyriewen16 小时前
我让AI给前端项目做了一次完整的Code Review——它和人类的差距,比我想的大得多
前端·javascript·ai编程