news 2026/5/4 4:41:18

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/5/1 9:53:32

【风电光伏功率预测】预测不是模型,是“账单”:风电光伏功率预测如何做成“可接入、可维护、可复盘”的SaaS?

过去几年&#xff0c;功率预测最容易陷入一个误区&#xff1a;把“模型效果”当成终点。但市场走到今天&#xff0c;功率预测早就不只是技术展示&#xff0c;它直接进入了“调度—交易—考核—结算”的链路&#xff1a;电力现货市场在加速推进、强调技术支持系统校验与连续运行…

作者头像 李华
网站建设 2026/5/1 12:15:14

活出“掌控感”:重建不疲惫的幸福日常

0. 咱们先聊个扎心的“隐形疲惫”哎&#xff0c;你有没有过这种感觉&#xff1f;明明这一天也没干什么惊天动地的大事&#xff0c;没搬砖也没跑马拉松&#xff0c;但到了晚上十点&#xff0c;整个人就像被抽了筋似的&#xff0c;瘫在沙发上一根手指头都不想动。 脑子里像有一团…

作者头像 李华
网站建设 2026/5/1 1:56:55

分体式位移传感器:工业精密测量的“空间魔术师”

在工业自动化、智能制造与高端装备领域&#xff0c;位移测量是保障生产精度与效率的核心环节。然而&#xff0c;当测量场景面临高温、高压、空间狭窄或强电磁干扰等极端条件时&#xff0c;传统一体式位移传感器常因安装受限、环境适应性差而“力不从心”。此时&#xff0c;分体…

作者头像 李华
网站建设 2026/5/3 3:43:42

计算机毕设java飞机票管理系统 基于Java的航空票务管理平台设计与实现 Java技术驱动的航班票务管理系统开发

计算机毕设java飞机票管理系统7h5v09 &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。随着互联网的普及和航空出行的日益频繁&#xff0c;传统的飞机票管理模式已难以满足现代用户…

作者头像 李华
网站建设 2026/5/3 18:58:09

HY-MT1.5-1.8B自动化部署:CI/CD流水线集成实战

HY-MT1.5-1.8B自动化部署&#xff1a;CI/CD流水线集成实战 1. 为什么需要为HY-MT1.8B构建CI/CD流水线&#xff1f; 你有没有遇到过这样的情况&#xff1a;模型在本地跑得好好的&#xff0c;一上测试环境就报CUDA内存不足&#xff1b;开发同学改了提示词模板&#xff0c;测试同…

作者头像 李华
网站建设 2026/5/3 6:16:26

2026必备!自考论文神器TOP10:AI论文工具深度测评与推荐

2026必备&#xff01;自考论文神器TOP10&#xff1a;AI论文工具深度测评与推荐 2026年自考论文写作新趋势与工具测评方向 随着人工智能技术的不断进步&#xff0c;越来越多的自考学生开始依赖AI论文工具来提升写作效率与质量。然而&#xff0c;面对市场上琳琅满目的选择&…

作者头像 李华