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属性被删除了,而是执行删除没找到要删除的也算删除成功 ;

相关推荐
Raas10022 分钟前
AI网关部署方案?从部署到上线全流程
java·开发语言·人工智能·gateway·ai网关·企业级ai网关·企业级ai产品
程序员大阳1 小时前
副队长JavaScript教程(50)-DOM:网页开发的起点
javascript·dom·es·节点·概念·document·关系
专注仿真1 小时前
线性回归和逻辑回归算法详解
开发语言·人工智能·python·大模型训练·控制算法
jimy12 小时前
C++ 中的 `T&&`:右值引用与转发引用
开发语言·c++
呆呆虫122 小时前
用 orjson 加速 SerpBase 响应解析:基准对比与注意事项
开发语言·php
心疼你的一切3 小时前
Python自动发邮件实战定时发报表
大数据·开发语言·python
Wang's Blog4 小时前
Java 项目实战:交友项目 - 用户体系集成总结
java·开发语言·交友
中科三方4 小时前
IPv6检测常见问题:AAAA记录检测不通过是什么原因?
开发语言·php
沫璃染墨5 小时前
从零入门计算机网络系列(十一):HTTP协议进阶——从重定向原理到GET/POST与Fiddler抓包
linux·服务器·开发语言·网络·c++·tcp/ip·html
刚入门的大一新生5 小时前
Linux-线程互斥
java·开发语言