news 2026/1/31 12:09:50

05.this的绑定规则、优先级、和相关面试题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
05.this的绑定规则、优先级、和相关面试题

关于闭包内存泄漏案例说明

前面讲的案例里面说下面数组占据的大小是 4M,但是有同学有疑惑:number 占据的大小不是 8 byte,不应该是 8M 吗?

functioncreateFnArray(){// 整数占据 4 个字节// arr 占据内存大小:1024 * 1024 * 4 = 4Mvararr=newArray(1024*1024).fill(1)returnfunction(){console.log(arr.length)}}

为什么是 4M 而不是 8M?这涉及到 V8 引擎的内存优化机制:下面是我通过 ai 以及老师总结的梳理

  1. JavaScript Number 类型的理论大小

    • JavaScript 中的number类型在规范上是 64 位浮点数(IEEE 754 双精度浮点数)
    • 理论上每个 number 应该占据8 字节
  2. V8 引擎的 SMI 优化

    • V8 引擎为了优化性能,引入了SMI(Small Integer)优化机制
    • SMI 范围:-2³¹2³¹-1(即 -2,147,483,648 到 2,147,483,647)
    • 对于在这个范围内的整数,V8 会使用32 位整数(4 字节)来存储,而不是 64 位浮点数
  3. 数组元素类型优化

    • 当数组中的所有元素都是小整数时,V8 会将数组优化为Packed SMI Elements类型
    • 这样每个元素只需要 4 字节,而不是 8 字节
    • fill(1)填充的是整数 1,属于 SMI 范围,所以每个元素占据 4 字节
  4. 内存计算

    • 数组长度:1024 × 1024 = 1,048,576 个元素
    • 每个元素:4 字节(SMI 优化)
    • 总内存:1,048,576 × 4 = 4,194,304 字节 ≈4MB

SMI 工作原理

V8 在内部使用标记位(标记指针)(tagged pointer)来区分,用于在指针中嵌入类型信息:

  • SMI 存储:将整数左移 1 位(乘以 2),最低位设为 0 作为标记,直接放在指针位置。
  • 非 SMI:最低位设为 1,其余位存储指向堆对象的真实指针。

对比示例

// 情况 1:SMI(小整数)vara=1存储:指针值=(1<<1)|0=2二进制:...0010← 最低位=0(表示这是SMI) 读取:值=2>>1=1// 情况 2:非 SMI(大整数或浮点数)varb=2147483648步骤:1.在堆中分配8字节:地址=0x123456782.存储数字到堆中3.指针值=0x12345678|1=0x12345679二进制:...1001← 最低位=1(表示这是指向堆对象的指针) 读取:1.检查最低位:0x12345679&1=1(是真实指针)2.恢复地址:0x12345679&~1=0x123456783.从堆地址读取8字节的值

示例:

// ✅ SMI(4 字节)vara=1varb=100varc=-100vard=2147483647// SMI 最大值// ❌ 非 SMI(8 字节)vare=2147483648// 超出 SMI 范围varf=1.5// 浮点数varg=Infinity// 特殊值varh=NaN// 特殊值
// 使用大整数(超出 SMI 范围),会使用 8 字节vararr1=newArray(1024*1024).fill(2147483648)// 超出 SMI 范围// 此时每个元素占据 8 字节,总内存约为 8M// 使用浮点数,也会使用 8 字节vararr2=newArray(1024*1024).fill(1.5)// 浮点数// 此时每个元素占据 8 字节,总内存约为 8M// 使用小整数(SMI 范围),使用 4 字节vararr3=newArray(1024*1024).fill(1)// SMI 优化// 此时每个元素占据 4 字节,总内存约为 4M

综上,这是 JavaScript 规范与引擎实现之间的差异,V8 引擎为了优化内存和性能而做的优化,属于引擎层面的实现细节

  • 小整数(SMI):4 字节存储
  • 大整数或浮点数:8 字节存储

v8 源码: https://github.com/v8/v8

内置函数的绑定

有些时候,我们会调用一些 JavaScript 的内置函数,或者一些第三方库中的内置函数

  • 这些内置函数会要求我们传入另外一个函数
  • 我们自己并不会显示的调用这些函数,而且 JavaScript 内部后者第三方库内部会帮助我们执行
  • 这些函数中的 this 是如何绑定的?
// 1.setTimeoutsetTimeout(function(){console.log(this)// window},2000)// 2.监听点击constboxDiv=document.querySelector('.box')boxDiv.onclick=function(){console.log(this)// boxDiv}boxDiv.addEventListener('click',function(){console.log(this)// boxDiv})// 3.数组.forEach/map/filter/findvarnames=['a','b','c']names.forEach(function(item){console.log(item,this)// window})names.forEach(function(item){console.log(item,this)// ['a', 'b', 'c']},names)

规则优先级

如果一个函数调用位置应用了多条规则,优先级谁更高?

1、默认规则的优先级最低

因为存在其他规则时,就会通过其他规则的方式来绑定 this

2、显示绑定优先级高于隐式绑定

varobj={name:'obj',foo:function(){console.log(this)},}obj.foo()// obj// call、apply 的优先级高于隐式绑定obj.foo.call('kaimo')// String {'kaimo'}obj.foo.apply('kaimo')// String {'kaimo'}// bind 的优先级高于隐式绑定functionfoo(){console.log(this)}varobj2={name:'obj2',foo:foo.bind('kaimo2')}obj2.foo()// String {'kaimo2'}

3、new 绑定优先级高于隐式绑定

varobj={name:'obj',foo:function(){console.log(this)},}// new 的优先级高于隐式绑定varf=newobj.foo()// foo {}

4、new 绑定优先级高于显示绑定

// 结论:new 关键字不能和 apply、call 一起来使用functionfoo(){console.log(this)}// new 绑定优先级高于 bind 绑定varbar=foo.bind('kaimo')varobj=newbar()// foo {}

new 绑定 > 显示绑定(apply、call、bind) > 隐式绑定(obj.foo()) > 默认绑定(独立函数调用)

this 规则之外 - 忽略显示绑定

如果在显示绑定中,我们传入一个null或者undefined,那么这个现实绑定会被忽略,使用默认规则。

functionfoo(){console.log(this)}// apply/call/bind 当传入 null、undefined 时,自动将 this 绑定成全局对象foo.apply(null)// windowfoo.call(undefined)// windowvarbar=foo.bind(null)bar()// window

this 规则之外 - 间接函数使用

创建一个函数的间接引用,这种情况使用默认绑定规则。

varobj1={name:'obj1',foo:function(){console.log(this)}};varobj2={name:'obj2'};// obj2.foo = obj1.foo;// obj2.foo(); // obj2// 间接调用:(obj2.foo = obj1.foo)() 实际上是在调用返回的函数引用,而不是作为对象的方法调用// 属于独立函数调用(obj2.foo=obj1.foo)();// window

箭头函数 arrow function

箭头函数是 ES6 之后增加的一种编写函数的方法,并且它比函数表达式要更加简洁。

  • 箭头函数不会绑定 this、arguments 属性
  • 箭头函数不能作为构造函数来使用(不能和 new 一起来使用,会抛出错误)

箭头函数如何编写?

// () 参数// => 箭头// {} 函数的执行体varfoo=(num1,num2,num3)=>{}// 高阶函数在使用时,也可以传入箭头函数[1,2,3].forEach(()=>{});

箭头函数的编写优化

// 常见的简写// 简写1:如果参数只有一个,() 可以省略[1,2,3].forEach(item=>{console.log(item)});// 简写2:如果函数执行体只有一行代码,{} 可以省略,并且它会默认将这行代码的执行结果作为返回值[1,2,3].forEach(item=>console.log(item));varnewNums=[1,2,3].filter(item=>item%2===0)varresult=[1,2,3].filter(item=>item%2===0).map(item=>item*100).reduce((preValue,item)=>preValue+item)// 简写3:如果一个箭头函数只有一行代码,并且返回一个对象,这个时候如何编写简写varbar=()=>({name:'kaimo313',age:18})

this 规则之外 - ES6 箭头函数

箭头函数不使用 this 的四种标准规则(也就是不绑定 this),而是根据外层作用域来决定 this。

// 1、测试箭头函数中的 this 指向varname='kaimo'varfoo=()=>{console.log(this)}foo()// windowvarobj={foo:foo}obj.foo()// windowfoo.call('kaimo313')// window// 2、应用场景varobj2={data:[],getData:function(){// 模拟发送网络请求,将结果放到 data 里面// 在箭头函数之前的解决方案// var _this = this// setTimeout(function() {// var result = ['a', 'b', 'c']// _this.data = result// }, 2000)setTimeout(()=>{varresult=['a','b','c']this.data=result},2000)}}obj2.getData()

面试题一

varname="window"varperson={name:"person",sayName:function(){console.log(this.name)}}functionsayName(){varsss=person.sayName;sss();// window 独立函数调用person.sayName();// person 隐式调用(person.sayName)();// person 隐式调用(b=person.sayName)();// window 赋值表达式(独立函数调用)}sayName();

面试题二

varname="window";varperson1={name:"person1",foo1:function(){console.log(this.name)},foo2:()=>console.log(this.name),foo3:function(){returnfunction(){console.log(this.name)}},foo4:function(){return()=>{console.log(this.name)}}}varperson2={name:"person2"}person1.foo1();// person1 隐式绑定person1.foo1.call(person2);// person2 显示绑定优先级大于隐式绑定person1.foo2();// window 不绑定作用域,上层作用域是全局person1.foo2.call(person2);// windowperson1.foo3()();// window 独立函数调用person1.foo3.call(person2)();// window 独立函数调用person1.foo3().call(person2);// person2 最终调用返回函数时,使用的是显示绑定person1.foo4()();// person1 箭头函数不绑定this,上层作用域this是person1person1.foo4.call(person2)();// person2 上层作用域被显示的绑定了一个person2person1.foo4().call(person2);// person1 箭头函数不绑定this,上层作用域this是person1

面试题三

varname="window";functionPerson(name){this.name=name;this.foo1=function(){console.log(this.name)}this.foo2=()=>console.log(this.name);this.foo3=function(){returnfunction(){console.log(this.name)}}this.foo4=function(){return()=>{console.log(this.name)}}}varperson1=newPerson('person1');varperson2=newPerson('person2');person1.foo1();// person1 隐式绑定person1.foo1.call(person2);// person2 显示绑定优先级大于隐式绑定person1.foo2();// person1 箭头函数不绑定this,上层作用域this是person1person1.foo2.call(person2);// person1 箭头函数不绑定this,上层作用域this是person1person1.foo3()();// window 独立函数调用person1.foo3.call(person2)();// windowperson1.foo3().call(person2);// person2person1.foo4()();// person1person1.foo4.call(person2)();// person2person1.foo4().call(person2);// person1 箭头函数不受 call 影响,仍然指向词法作用域中的 person1

面试题四

varname="window";functionPerson(name){this.name=name;this.obj={name:'obj',foo1:function(){returnfunction(){console.log(this.name)}},foo2:function(){return()=>{console.log(this.name)}}}}varperson1=newPerson('person1');varperson2=newPerson('person2');person1.obj.foo1()();// windowperson1.obj.foo1.call(person2)();// windowperson1.obj.foo1().call(person2);// person2person1.obj.foo2()();// objperson1.obj.foo2.call(person2)();// person2person1.obj.foo2().call(person2);// obj
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/31 9:09:02

CE、CCC、COC 差异与合规指南

在全球化贸易与国内市场准入体系中&#xff0c;CE 认证、CCC 认证、COC 认证是三类核心产品合规认证&#xff0c;直接决定商品能否进入目标市场流通&#xff0c;三者在适用范围、认证规则和核心目的上差异显著。CE 认证是欧盟的产品安全准入标志&#xff0c;适用于所有进入欧盟…

作者头像 李华
网站建设 2026/1/30 15:19:03

基于Springboot+Vue的基层智能化人员调度系统源码文档部署文档代码讲解等

课题介绍 本课题旨在研发基于SpringBootVue前后端分离架构的基层智能化人员调度系统&#xff0c;聚焦乡镇、社区、园区等基层场景&#xff0c;解决传统人员调度中信息闭塞、派单低效、资源匹配无序、过程无追溯等痛点。系统面向基层工作人员与管理人员&#xff0c;适配应急值守…

作者头像 李华
网站建设 2026/1/30 3:29:35

深度测评8个一键生成论文工具,专科生轻松搞定毕业论文!

深度测评8个一键生成论文工具&#xff0c;专科生轻松搞定毕业论文&#xff01; AI 工具的崛起&#xff0c;让论文写作不再难 随着人工智能技术的不断进步&#xff0c;越来越多的 AI 工具开始渗透到学术写作领域&#xff0c;为学生和科研工作者提供了前所未有的便利。尤其是在降…

作者头像 李华
网站建设 2026/1/30 16:09:57

计算机毕设java高校评优管理系统 基于Java的高校评优管理平台设计与实现 Java技术驱动的高校评优管理系统开发

计算机毕设java高校评优管理系统0u15n9&#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。 随着高校教育信息化的不断推进&#xff0c;传统的评优管理方式已经难以满足现代高校高效…

作者头像 李华
网站建设 2026/1/30 23:55:35

App项目后台如何用 XinServer 实现自动化测试?

App项目后台如何用 XinServer 实现自动化测试&#xff1f; 最近跟几个做移动端的朋友聊天&#xff0c;发现一个挺普遍的现象&#xff1a;大家花大把时间把App界面做得漂漂亮亮&#xff0c;交互丝滑流畅&#xff0c;但一到要对接后台、联调接口的时候&#xff0c;项目进度就肉眼…

作者头像 李华
网站建设 2026/1/27 18:28:20

微信记录2019(三)

有感今春四五次狂风大雨&#xff0c;世间之果实&#xff0c;非人为护之外&#xff0c;皆大浪淘沙之精华也&#xff01;06031103技术日益精进&#xff0c;身体日益减损&#xff0c;消瘦&#xff0c;沉重&#xff0c;易困乏&#xff0c;不易集中注意力&#xff0c;混混噩噩&#…

作者头像 李华