JS面试经:继续js的面试之路
java基础知识

接着上一期我们继续来倒腾有关变量提升的js考题,话不多说,先看代码

fn();
function fn() { console.log(1); }
fn();
function fn() { console.log(2); }
fn();
var fn = function fn() { console.log(3); }
fn();
function fn() { console.log(4); }
fn();
function fn() { console.log(5); }
fn();



上述代码要执行下来首先弄清楚一点,函数是可以重复声明的,这就是函数的重载,这一点不同于java,py等静态语言,js函数重载是被允许的,那么按照上一期的结论,带有 fun关键字的函数变量提提升--声明且赋值 ,所以第一,函数执行结果的值都会被最后一个覆盖,知道遇到var的关键字--只声明不赋值,执行到第三行函数,会重新执行console.log(3)这个代码,那么后面的函数结果都会使用这个代码的结果,所以上述结果为:
WeChat32fb701dc399a7a77e63136671fcad70.png

下面我们结合一下 es6的语法来看看变量提升,let定义 变量,cosnt定义常量,都不存在变量提升,let带来块级作用域的概念,声明的变量只在块级范围内有效

{
   console.log(a) // => Error: a is not defined
   let a = 1
 }

来看一个比较经典的题目

for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1)

}
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1)
}

要得出上述代码的执行结果就要比较var和let的不同,两个for循环结尾都用了setTimeout,使用var的代码因为setTimeout是一个异步,所以它拿到的是循环结束后的i的值,var的变量会被覆盖掉所以最后的i值是5,而且一共循环了3次(0,1,2),所以会打印3个3;
而let在代码块中都有自己的作用域,所以在for循环中的表达式中使用let它的每一个值都会单独存在一个独立的作用域中不会被覆盖掉,所以在for循环中使用了let声明循环变量,所以每一个值都会存在于单独的作用域不会被覆盖掉,因此,循环结束后得到的值是0,1,2
其实上面的测试题理解起来也不太容易,涉及到闭包和异步,我先拿出这道题就是展示下var和let的不同,用起来会差别很大,以后我会再拿此题详解;
既然说到闭包,那就有必要聊一下,前端笔试题对闭包的考察也是乐此不疲的,我们先上两道题:
第一题:

{
console.log(a, b)
var a = 12,
b = 12;
function funA() {
console.log(a, b);
var a = b = 13;
console.log(a, b);
}

funA();
console.log(a, b);
}



第二题:

console.log(a, b, c)
var a = 12,
b = 13,
c = 14
function fn(a) {
console.log(a, b, c)
a = 100;
c = 200;
console.log(a, b, c)
}
b = fn(10);
console.log(a, b, c);

先放一下两道题,我们看一下官方对闭包的定义:

函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在 JavaScript 中,每当函数被创建,就会在函数生成时生成闭包。

引用一下阮一峰老师的话和代码

我的理解是,闭包就是能够读取其他函数内部变量的函数。
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。

看一下阮一峰老师给出的简单易懂的例子

 var n=999;
  function f1(){
    alert(n);
  }
  f1(); // 999


function f1(){
    var n=999;
  }
  alert(n); // error

从上面的例子看出来,函数可以访问外到部的变量进行一些操作,而函数自己内部的变量就被保护起来了,外部访问不到,这就是私有变量的保护;
现在来看一下两道题,第一题有个细节,函数内部var a = b = 13等价于var a=13 b=13,所以funA第一个console函数内部没有声明b,那么b就会在作用域链的规则下向外部查找,不太明白的可自行百度作用域链,这里就不再赘述,以后会详细讲到;那么b就会取到外部全局变量b的值为12,执行结果为:
WeChat31fd336469a42934f2694e2f87f1fadf.png
第二题需要注意的细节是b = fn(10); fn()函数没有return值,所以这里会吧 undefined赋值给b,执行fn(10)就等于把形参a的值和10关联了,所以函数内部a的值就是10,贴一下结果:
WeChatcc77966746f233f2cea9b44e3000a635.png

这些笔试题其实概念懂了都好理解,就是要注意一些细节,多个知识点揉合在一起所以看起来似乎有些难度,多多思考多多实践,你的笔试水平就会大大提高

暂无评论