遇到了几道关于作用域的前端小题

152 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

在平时的开发过程中,可能考虑各个变量的作用域问题比较少,但是当你找工作时,就会经常遇到这类题目。这里我去看了一下面试题,学到老活到老,学习参考链接:前端面试问题

其中有关于立即执行函数表达式(IIFE)的作用域问题那是更加的层出不穷了。

立即执行函数表达式(IIFE)

立即执行函数,就是在定义函数的时候直接执行,这里不是申明函数而是一个函数表达式

在 JavaScript 中,每一个函数在执行时都会产生一个新的执行环境。由于在函数中定义的变量和函数只能在内部访问而不能被外部访问。这一执行环境调用的函数提供了一个非常简单的方法来创建私有作用域

下面是一个简单的立即执行函数表达式写法:

(function () {
    ...
})();

这里方法的立即执行()前的内容一般需要加括号包围起来,这是告诉解析器这是一个被括号包裹的函数表达式,如果像下面这样写是错误的,报的错误是:Uncaught SyntaxError: Unexpected token ')'

function a() {
    console.log(1);
}();

如果不想使用(),可以在方法前通过=,|,&这些方式来让表达式生效

i = function(){ console.log(1); }();
true && function () { console.log(1); }();
0, function(){ console.log(1); }();

当然,也可以在方法前添加一个一元化运算符,这样做依旧可以生效

+function a() {
    console.log(1);
}();

接下来就看看具体的问题吧

问题1

非严格模式下执行结果:

(function a () { a = 2; console.log(a); })();

答案:

ƒ a () { a = 2; console.log(a); }

解析: 这里的立即执行的函数表达式内部会优先寻找当前作用域下的内容,内部的a = 2是变量a是属于全局变量,而表达式a属于当前作用域,所以会优先执行打印出函数表达式a。

如果使用的是以下语句,那么会打印出2,因为var a是在当前作用域下定义的。

(function a () { var a = 2; console.log(a); })();

补充: 同级作用域下,正常定义变量a和函数a,之后打印a,会优先打印变量。 如果打印a在定义之前,那么会打印函数,因为函数的提升是整个代码块提升到它所在的作用域的最开始执行。

问题2

非严格模式下执行结果:

(function () { var a = (b = 5); })();
console.log(b);
console.log(a);

答案:

5
Uncaught ReferenceError: a is not defined

解析: 因为IIFE中的(b = 5)是全局变量定义,在外部打印时找不到私有作用域中的变量a,但是可以找到全局作用域中的变量b。

补充: 严格模式下,不能使用未声明的变量,比如a = 5;这种定义变量时会出错,必须加上var等变量声明方式。

问题3

非严格模式下执行结果:

data = '101';
var Fun = {
    data : '123',
    getData() {
        return this.data;
    }
}
console.log(Fun.getData());
newFunGet = Fun.getData;
console.log(newFunGet());  

答案:

5
Uncaught ReferenceError: a is not defined

解析: 这里其实是this指向问题,不同的函数执行环境。this取决于其被谁调用了,而不是被谁定义了 当Fun调用getData方法时,this指向的是Fun。而newFunGet中调用getData方法this指向的是window对象,所以此时的data是外面的全局变量


这就是几道简单的作用域小题,边学习边记笔记。