填坑-十万个为何?(13)

简介:不少概念不清或忘记,从新构建本身的知识体系。天天问本身1~多个问题。我是菜鸟 成为大神之路!javascript

1. 经典面试题 for(var i=0;i<=3;i++){ setTimeout(function() { console.log(i) }, 10);}打印结果?分析?

for(var i = 0; i < 10; i++) {
	console.log(new Date(),i);
    setTimeout(() => {
        console.log(new Date(),i)
    }, 1000);//一秒
}
答案:打印1010

这道题涉及了异步、做用域、闭包

😀settimeout是异步执行,1ms后往任务队列里面添加一个任务,只有主线上的所有执行完,才会执行任务队列里的任务,
当主线执行完成后,i是10,因此此时再去执行任务队列里的任务时,i所有是10了。

😁对于打印10次是:每一次for循环的时候,settimeout都执行一次,可是里面的函数没有被执行,而是被放到了任务队列里面,
等待执行,for循环了10次,就放了10次,当主线程执行完成后,才进入任务队列里面执行。
(注意:for循环从开始到结束的过程,须要维持几微秒或几毫秒。)
复制代码

① 若要输出从0到9,将 var 改成 let
for(let i = 0; i < 10; i++) {
	console.log(new Date(),i);
    setTimeout(() => {
        console.log(new Date(),i)
    }, 1000);//一秒
}

当我把var 变成let 时
😂打印出的是:0~10当解决变量做用域,由于for循环头部的let不只将i绑定到for循环快中,
事实上它将其从新绑定到循环体的每一次迭代中,确保上一次迭代结束的值从新被赋值。

😂setTimeout里面的function()属于一个新的域,经过 var 定义的变量是没法传入到这个函数执行域中的, 经过使用 let 来声明【块变量】,这时候变量就能做用于这个块,因此 function就能使用 i 这个变量了; 😂这个匿名函数的参数做用域 和 for参数的做用域不同,是利用了这一点来完成的。 这个匿名函数的做用域有点相似类的属性,是能够被内层方法使用的。 复制代码
② 若要输出从0到9,改写为闭包

闭包相关解释下一问。html

// 使用闭包
for(var i = 0; i < 10; i++) {
    console.log(new Date(),i);
    (function (i) {
        setTimeout(() => {
            console.log(new Date(),i);
        }, 1000);
    })(i);
}
复制代码

2.闭包的做用域?代码执行过程?

常常遇到闭包的相关问题java

代码一:
// 以1问中例子为例
for(var i = 0; i < 10; i++) {
    console.log(new Date(),i);
    (function (i) {
        setTimeout(() => {
            console.log(new Date(),i);
        }, 1000);
    })(i);
}
代码一是闭包,写为代码二不为闭包的形式,(function(i){})(i) '理解为自执行函数' 自执行函数的相关参考在12天和参考文章中,以后我会对着一块内容进行学习👍。

代码二:
var fun = function(x){
	setTimeout(() => {
            console.log(new Date(),x);
        }, 1000);
	}

for(var i = 0; i < 10; i++) {
    console.log(new Date(),i);
    fun(i);
}
复制代码
JavaScript 变量能够是局部变量或全局变量。
私有变量能够用到闭包。

什么是闭包:
> 就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。
> 就是函数的“堆栈”在函数返回后并不释放,咱们也能够理解为这些函数堆栈并不在栈上分配而是在堆上分配
> 当在一个函数内定义另一个函数就会产生闭包
> "注:变量声明时若是不使用 var 关键字,那么它就是一个全局变量,即使它在函数内定义。"

注意:一般人们对闭包的理解是不彻底的,认为在 JavaScript 中只有嵌入的函数才是闭包。但其实任何拥有 free variable(自由变量)
的函数都是以闭包的形式存在的。由于本质上,闭包是 free variable 问题的一种解决方案。http://liximomo.github.io/javascript-closure

闭包的注意点
1)因为闭包会使得函数中的变量都被保存在内存中,内存消耗很大,因此不能滥用闭包,不然会形成网页的性能问题,在IE中可能致使内存泄露。
解决方法是,在退出函数以前,将不使用的局部变量所有删除。
2)闭包会在父函数外部,改变父函数内部变量的值。因此,若是你把父函数看成对象(object)使用,把闭包看成它的公用方法(Public Method),
把内部变量看成它的私有属性(private value),这时必定要当心,不要随便改变父函数内部变量的值。
复制代码

闭包须要注意的两种状况----函数做为返回值,函数做为参数传递。git

例子:函数做为返回值github

1. function greeting(name) {
2. 		var text = 'Hello '; // local variable
 		// 每次调用时,产生闭包,并返回内部函数对象给调用者
3. 		return function() {return text += name; }
 	}
 	
4. 	var sayHello=greeting("Closure");
 	
5. 	document.write(sayHello());
6. 	document.write("<br>");
7. 	document.write(sayHello());
8. 	document.write("<br>");
9. 	document.write(sayHello());
10. document.write("<br>");
11. document.write(sayHello());
12. document.write("<br>");
13. document.write(sayHello());// 经过闭包访问到了局部变量text
	
代码解析:
> 执行第4行时第一行的函数运行一次,返回内嵌函数引用做为第4行sayHello变量的值。
> 以后的第5到13行执行的函数操做其实只是执行sayHello指向的函数(即返回的内嵌函数)。
> 解释text为何能自增,闭包的概念。

复制代码

例子:函数做为参数传递面试

1. var num = 10;

2. var fun = function(var num){
3.    console.log(num);
   }
4. !function(f){
5.     var num = 100;
6.     f(num);
7. }(fun)

代码解析:
> 第四行'!'表示高优先级,被'!'标注的先执行。
> 第7行将fun指向的引用2行函数传给参数f在函数中执行f(?)函数,此时log出来的值是10。
> 解释看js做用域
复制代码

3.var let const的区别?

① 什么是var的变量提高补充2019年1月5日23:31:41 来源网易课堂
'代码1'
var a = 10;
function foo(){
    console.log(a);//打印:10
}
'代码2'
var a = 10;
function foo(){
    console.log(a);//打印:undefined
    var a = 5;
}
'问代码2为何输出的是undefined这里变量提早了,实际代码至关于以下'
'代码3'
var a = 10;
function foo(){
    var a;
    console.log(a);//打印:undefined
    a = 5;
}
复制代码
② let 声明的变量只在它所在的代码块有效
function demo(){
  {
    var a = 12;
    let c = 10;
    console.log(a);//这里会打印出12;
    console.log(c);//这里会打印出10;
  }
  console.log(a);//这里会打印出12
  console.log(c);//这里打印出的内容为 "c is not defined";
  //说明声明的c变量只在{}代码块中可以访问,其余地方都访问不到;
}
demo();
复制代码
③ let不存在变量提高

let 不像var 那样会发生 '变量提高' 现象,所以,变量须要先声明而后再使用,不然报错;bash

// var 的状况
console.log(vardata);  // undefined
var vardata = 2;

// let的状况;
console.log(letdata);  // letdata is not defined 报错
let letdata = 2;
复制代码
④ let暂时性死区

快级做用域内存在let命令,它所声明的变量就绑定在这个区域,再也不受外部影响;闭包

var tmp = 123;
if (true) {
  tmp = 'abc';
  let tmp;
  console.log(tmp); // tmp is not defined
}
复制代码
⑤ let不容许重复声明

let 不容许在相同做用域内,重复声明同一个变量。less

function foo() {
  let v = 10;
  var v = 1;//Identifier 'v' has already been declared
  console.log(v);
}
foo();

function foo1() {
  let v1 = 10;
  let v1 = 1;//Identifier 'v1' has already been declared
  console.log(v1);
}
foo1();
复制代码
⑥ const 声明一个只读的常量,一旦声明,常量的值就不容许改变
⑦ const 一旦声明了变量,就必须初始化,不能留到之后赋值。若是使用const声明一个变量,可是不赋值,也会报错
⑧ const 的做用域与let命令相同;只在声明所在的块级做用域内有效。
⑨ const 不可重复声明 (和let同样)

参考文章:
let的含义及let与var的区别
闭包文档
博客-深刻理解javascript原型和闭包
JS关于闭包
函数 + 函数建立时的环境 = 闭包异步

相关文章
相关标签/搜索