前端面试(四):一起来看一下这一道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,并用一个立即执行函数来为其赋值,立即函数的参数numobj.num即2。num是立即执行函数的参数,因为传进来是一个值,而非引用,所以这里num的作用域是函数内部的作用域,num的变化不会影响到全局作用域中的numobj.num

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

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

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

函数中this指向的是函数调用者,假设闭包函数是被obj调用执行的话,那么闭包函数内this的指向为objthis.num += n中的this.num即 为obj.num, num++中变量num仍然为上层函数作用域中的立即执行函数参数numconsole.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上下文就这样理解 😺🐱🐟
相关推荐
一颗花生米。2 小时前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
学习使我快乐012 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio19952 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
勿语&3 小时前
Element-UI Plus 暗黑主题切换及自定义主题色
开发语言·javascript·ui
黄尚圈圈3 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水4 小时前
简洁之道 - React Hook Form
前端
正小安6 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch7 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光7 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   7 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发