前端面试(四):一起来看一下这一道console.log输出

前言

4月10日下午14:44, 我结束了今日的两场前端暑期实习生面试,面对没有offer的情况,加之刚刚面试被问到的崩溃的心理,还有未来几天的几场重要面试,疲惫的心灵很想得到放松。在躺了一个小时后,我心想,还是不要放弃自己,只是遇到了一点点的挫折,爬起来再向前走就好。

于是我想在这个有点昏暗的下午,把上午有趣的一道面试题解析一下,希望遇到相似问题的大家以及我,不用像我今天一样被绕的头晕。(我写的有点凌乱,希望有前辈可以指正)

面试题

请看下面的js代码,并写一下输出(在浏览器的执行环境下)

js 复制代码
var num = 1 
var obj = {num: 2 } 
obj.fn = (function (num) { 
    this.num = num * 4 
    num++ 
    return function (n) { 
        this.num += n 
        num++ 
        console.log(num) 
    }
})(obj.num) 

var fn = obj.fn 
fn(6) 
obj.fn(7) 
console.log(num)
console.log(obj.num)

思路

现在我们来捋一下这个代码的执行过程吧。

  1. var num = 1 ,声明了一个全局变量num,并将其赋值为1

  2. var obj = {num: 2 } ,声明了一个全局对象obj,其属性num的值为2

js 复制代码
 obj.fn = (function (num) { 
     this.num = num * 4 
     num++
     return function (n) { 
         this.num += n 
         num++ 
         console.log(num) 
     }
 })(obj.num) 

上这段代码为obj新增了一个属性fn,并用一个立即执行函数来为其赋值,立即函数的参数num是obj.num即2。num是立即执行函数的参数,因为传进来是一个值,而非引用,所以这里num的作用域是函数内部的作用域,num的变化不会影响到全局作用域中的num和obj.num。

this.num = num * 4,这里的this是指向全局对象的,因为立即执行函数是在全局作用域下执行的window.num = this.num = 立即执行函数的参数num * 4 = 2 * 4 = 8。

num++,这里立即执行函数num的值为2++=3。

在返回的闭包函数中,函数接收一个参数n,目前看来,闭包函数是真正赋值给obj的函数。

函数中this指向的是函数调用者,假设闭包函数是被obj调用执行的话,那么闭包函数内this的指向为obj,this.num += n中的this.num即 为obj.num, num++中变量num仍然为上层函数作用域中的立即执行函数参数num。console.log(num)则会打印立即执行函数参数num的值。

现在闭包函数还未执行,我们梳理一下这几个num变量的情况, 其中num0 === num3:

num 注释 作用域 值
num0 全局变量num 全局作用域 8
num1 obj.num obj 2
num2 立即执行函数的参数num 立即执行函数的作用域 3
num3 立即执行函数的this.num 全局作用域 8
num4 闭包函数的this.num 函数调用者的作用域,未调用未知 未知
  1. var fn = obj.fn用一个全局变量fn接收了obj.fn这个函数。

  2. fn(6)全局变量fn直接调用了方法,并传入参数n=6,在这里闭包函数的调用者为全局对象。num0 = this.num = 8(num0) + 6(n) = 14; num2 = num2++ = 4; 所以console.log输出num2为4,其余的变量情况如下:

    num 注释 作用域 值
    num0 全局变量num 全局作用域 14
    num1 obj.num obj 2
    num2 立即执行函数的参数num 立即执行函数的作用域 4
    num3 立即执行函数的this.num 全局作用域 8
    num4 闭包函数的this.num 全局作用域 8
  3. obj.fn(7)中obj调用了fn,并传入参数n=7,在这里闭包函数的调用者为obj。num1 = this.num = 2(num1) + 7(n) = 9; num2 = num2++ = 5; 所以输出num2为5,其余的变量情况如下:

    num 注释 作用域 值
    num0 全局变量num 全局作用域 14
    num1 obj.num obj 9
    num2 立即执行函数的参数num 立即执行函数的作用域 5
    num3 立即执行函数的this.num 全局作用域 8
    num4 闭包函数的this.num obj 9
  4. console.log(num)输出全局变量中的num即num0,14。

  5. console.log(obj.num)输出9。

最终的输出是 4 5 14 9

知识点

这道面试题目的代码只有十多行,但是其中考察的知识有很多。包括但不限于

  • 函数的参数作用域
  • js中this的指向问题
  • 闭包和作用域

函数的参数以及作用域

  • 函数里面的this指向函数的调用者。
  • 函数的参数存在于函数内部作用域中。

js中this指向问题

juejin.cn/post/735291...

闭包和作用域

闭包可以让外界访问到内部作用域中的变量。在这里由于闭包函数的存在,使得立即函数的参数变量num可以被继续访问到。

扩展

如果这段代码的执行环境为node,输出会不会不一样?

参考文档

  1. # 总结出五种场景下JavaScript中的this指向,覆盖项目中各种情况的this指向
  2. # this上下文就这样理解 😺🐱🐟
相关推荐
可乐鸡翅yeah_1 小时前
FFmpeg 生成 HLS 独立分片 independent‑segments 参数到底有什么用
javascript·ffmpeg·音视频·safari·m3u8
福兮说1 小时前
canvas 旋转图片的六个坑:四角被裁、Math.ceil 多出 1px 黑边、JPG 角发黑、翻转方向反了
前端·javascript·图像处理·canvas
Ai-_Man2 小时前
您您这可以把Grok的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。AI导出鸭
javascript·人工智能·ai·小程序·电脑
传人once2 小时前
多图片上传预览功能如何写
前端·css·html·jquery·html5
Eric.463 小时前
Wan‑Animate+MiniMax-H3 本地部署 AI 漫剧流水线:8G 显存动作迁移与动态分镜工程实战
前端·人工智能·comfyui·ai漫剧
liangshanbo12153 小时前
JavaScript 异步核心主线
javascript·事件循环·异步操作
传人once4 小时前
悬停旋转放大和位移效果如何写
javascript·css·动画
库拉镜像AI牛牛4 小时前
短剧内容自动化生产:知漫剧工作室落地教程
大数据·服务器·前端·人工智能·语音识别
律宏阔4 小时前
Flutter 列表图片内存优化:CachedNetworkImage 与 ClipRRect 的取舍
前端·flutter
行者全栈架构师4 小时前
【鸿蒙心迹】相册文搜图工程化落地:HarmonyOS 7.0 端侧 AI 检索全链路实战与 5 个踩坑解法
前端