JS函数的调用时机

236 阅读3分钟

调用时机

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

这段代码打印出了6个6,因为只声明一个i,那么在循环执行完后打印的i已经变成6了,如果想要打印出0,1,2...那么我们可以在循环体中声明一个变量来保存i,如

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

除了for和let配合的方法:

for(let i = 0; i<6; i++){
!function(j){
  setTimeout(()=>{
    console.log(i)
  },0)}()
}

创建函数

  • 具名函数function fn(){}
  • 匿名函数 let a =function(){} 注意如果let a =function fn(){}如果在等于号右边声明了一个具名函数那么他的作用于也在该等式右边
  • 箭头函数x=>x*2只有一个参数不需要用括号括起,只有一句输出自动帮你return
  • 构造函数let fn = new Function('x', 'y', 'return x+y')不推荐

函数声明会跑到最前面

形参和实参

形参等同于在函数内声明的变量。实参是的调用函数时把传给函数。所以形参的值就是个复制品。

作用域

JS函数创造了静态作用域(词法作用域),作用域的确定和函数执行无关,采用就近原则.也就是说在执行代码之前就确定了变量的归属。而我们知道变量的的声明都会分为创建、初始化、赋值三阶段,而且所有类型的声明都会把创建阶段提前到作用最前面。所以不管变量声明在作用域那个位置,只要被创建了,就能在该作用域找到变量。

因此下面的代码执行会返回2

let a =1 
function fn1(){
  function fn2(){
    console.log(a)
  }
let a =2
return fn2
}

let fn2 = fn1()
fn2()

全局变量和局部变量

局部变量,只要离开声明变量的代码块,那么变量就无法使用

全局变量是在顶层作用域中声明的变量和挂在全局对象window上的属性,如window.a

闭包

闭包:如果函数内的变量,根据语法作用域要引用到函数外的变量,就会被保存起来,像放进一个背包一样,跟随函数定义不会被销毁的.

调用栈

  • 压栈:进入函数前将环境压入栈中
  • 弹栈:执行完函数环境从栈中弹出
  • 爆栈:压入栈的环境过多
  • 栈: 这个栈类似于真正的栈,不同的是从下面开始顺序排放

this

let obj ={
name:deibo,
sayHi:function(){this.name}
}

当你在调用obj.sayHi()的时候,obj被当做实参将地址复制给this这个隐藏的形参.所以说this在函数调用之前不是一个真实的参数,他只是形式上代表将来要调用方法的对象.

  • obj.sayHi().call(obj) 这种写法就展示了这个过程.而obj.sayHi()这种写法只是默认将obj传入

箭头函数

没有this和arguments

立即执行函数

这种方式被用来声明一个局部作用域的变量,直到新版{let a =1}

!function(){
let a= 1;
}()