《JavaScript高级程序设计》读书笔记-第七章(函数表达式)

函数

函数提升


  • 函数声明提升
    执行代码之前会先读取函数声明。意思是可以把函数声明放到调用它的语句后面
sayHi()
function sayHi(){
  *****
}
  • 函数表达式
var functionName = function(arg0, arg1, arg2){
  *****
}

这个就不能把函数放到调用它的语句后面了,会报错

  • 理解函数提升的关键,就是理解函数声明和函数表达式之间的区别。
//不要这么写
if (condition) {
  function sayHi(){
    console.log('Hi')
  }
}else {
  function sayHi(){
    console.log('Hello')
  }
}

这在ECMAScript上属于无效语法,JavaScript引擎会尝试修正错误,将其转换为合理的状态。大多数浏览器会返回第二个声明,忽略condition。Firefox会在condition为true时返回第一个声明。

可以这样做,用函数表达式:

let sayHi
if(condition){
  sayHi = function(){
    console.log('Hi')
  }
}else {
  sayHi = function(){
    console.log('Hello')
}

递归


js在递归里面可以使用arguments,callee来防止函数名被置空的情况,例如:

function factorial(num) {
  if(num <= 1){
    return 1
  } else {
    return num * factorial(num - 1)
  }
}

var anotherFactorial = factorial
factorial = null
console.log(anotherFactorial(4))

上面factorial函数被置空之后,程序就会报错:


我们可以这样解决

function factorial(num) {
  if (num <= 1){
    return 1
  } else {
    return num * arguments.callee(num - 1)
  }
}

又或者是这样
创建一个名为f()的命名函数表达式

var factorial = function f(num) {
  if(num <= 1){
    return 1
  }else {
    return num * f(num-1)
  }
}

闭包


闭包是指有权访问另一个函数作用域中的变量的函数。
如何创建作用域链以及作用域链有什么作用的细节,对彻底理解闭包至关重要。

  • 函数的调用过程:
    1、创建一个执行环境execution context及相应的作用域链
    2、把作用域链赋值给一个特殊的内部属性[Scope]
    3、用this、arguments和其他命名参数的值来初始化函数的活动对象(activation object)

例如

function compare(value1,value2){
  if(value1 < value2){
    return -1
  }else if(value1 > value2){
    return 1
  }else{
    return 0
  }
}

书上的图

一般作用域链包含两个变量对象:本地活动对象以及全局变量对象
闭包不同
未完待续

你可能感兴趣的:(《JavaScript高级程序设计》读书笔记-第七章(函数表达式))