JavaScript高等程序设计-择要笔记-5

函数表达式和闭包

1. 函数声明的一个主要特性是函数声明提拔

如:

sayHi()
function sayHi () {
  console.log('hi')
}

2. 递归

递归函数是在一个函数经由过程名字挪用本身的情况下组成的。
如:

function factorial (num) {
  if (num <= 1) {
    return 1
  } else {
    return num * factorial(num - 1) // 这里存在强耦合,不太好
  }
}

比方下面的代码会致使它失足

var anotherFactorial = factorial
factorial = null
anotherFactorial(3) // 失足:factorial is not a function
arguments.callee 是一个指向正在实行函数的指针,可以做以下改良:
function factorial (num) {
  if (num <= 1) {
    return 1
  } else {
    return num * arguments.callee(num - 1)
  }
}

严厉形式下运用 arguments.callee 会失足。可以做以下改良

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

我的明白:这里的 f 只在函数内部有用,所以不会遭到外界影响,外部得不到这个变量。

(function test () {
  console.log('this is test')
})
test() // 报错。

用小括号括起来的函数声明在外部是得不到的,test()只要函数内部可以用

3. 闭包

闭包指有权接见另一个函数作用域中的变量的函数。
建立闭包的经常使用体式格局,就是在一个函数内部建立另一个函数。
如:

function createComparisonFunction (propertyName) {
  return function(obj1, obj2) {
    var value1 = obj1[propertyName]
    var value2 = obj2[propertyName]
    return value1 - value2
  }
}
var obj = [{age: 13}, {age: 29}, {age: 18}, {age: 37}, {age: 5}, {age: 14}]
var compare = createComparisonFunction('age')
var obj2 = obj.sort(function (a, b) {
  compare(a, b)
})

这个例子中,内部函数接见了外部函数的变量 propertyName,而且纵然被返回了在别的处所挪用,依然可以接见。
是由于内部函数的作用域链中包括了 createComparisonFunction 的作用域链。

由于闭包会照顾包括它的函数的作用域,因此会比别的函数占用更多的内存。

4. 闭包与变量

闭包作用域链的设置机制有一个副作用,闭包只能获得包括函数中任何变量的末了一个值,由于闭包保留的是全部变量对象,不是某个特别的变量。
如:

function createFunction () {
  var result = []
  for (var i = 0; i < 10; i++) {
    result[i] = function () {
      return i
    }
  }
  return result
}
// 返回数组中每一个函数的实行效果都是10

改良版:

function createFunction () {
  var result = []
  for (var i = 0; i < 10; i++) {
    result[i] = (function (num) {
      return function () {
        return num
      }
    }(i))
  }
  return result
}

如许就按预期来返回值了,这里经由过程马上实行函数把变量 i 的当前值作为参数通报到了内部闭包函数里,由于函数的基础范例参数是按值通报,
所以每一个内部闭包函数保留的值都是当前 i 值。

5. 关于闭包的this对象

var name = 'window';
(function () {
  this.name = 'fn'
  console.log(this.name) // 'fn'
  var obj = {
    name: 'obj',
    getFunc: function () {
      return function () {
        console.log(this.name)
      }
    }
  }
  obj.getFunc()() // 'fn'
}())

闭包函数的this指向它被挪用时的作用域对象。
每一个函数被挪用时都邑自动获得两个特别的变量:this 和 arguments。在挪用这两个变量时,只会搜刮到其运动对象为止。
this 的转变,如:

var name = 'the Window'
var obj = {
  name: 'obj',
  getName: function () {
    console.log(this.name)
  }
}
obj.getName(); // 'obj'
(obj.getName)(); // 'obj'
(obj.getName = obj.getName)(); // 'the Window'
var obj2 = {
  name: 'obj2'
}
(obj2.getName = obj.getName)(); // 'the Window'
// 这里我的明白是相当于一个马上实行函数,这个马上实行函数是在window环境下被实行的,所以返回window下的变量值。
obj2.getName = obj.getName
obj2.getName() // 'obj2'

6. 经由过程组织函数建立私有变量和特权要领

如:

function Person (name) {
  this.getName = function () {
    return name
  }
  this.setName = function (value) {
    name = value
  }
}
var ming = new Person('ming')
ming.name // undefined
ming.getName() // 'ming'
ming.setName('ming2')
ming.getName() // 'ming2'

申明:getName() setName() 在组织函数外部运用,只要这两个要领有权接见私有变量name,没有别的方法,由于它们作为闭包可以经由过程作用域链接见name
这类要领建立私有变量和特权要领有组织函数所共有的瑕玷——函数没有复用。

7. 静态私有变量

(function () {
  var name = ''
  Person = function (value) {
    name = value
  }
  Person.prototype.getName = function () {
    return name
  }
  Person.prototype.setName = function (value) {
    name = value
  }
}())
var ming = new Person('ming')
ming.getName() // 'ming'
ming.setName('ming2')
ming.getName() // 'ming2'
var li = new Person('li')
li.getName() // 'li'
ming.getName() // 'li' // 申明一切实例都是对作用域链中的 name 的援用

申明:这里马上实行函数里Person运用函数表达式来定义,而且没有运用 var , 是为了构成全局变量。

或许先在全局定义一下 Person也可以。
var Person = function () {}

注重:es6 中已经是块级作用域了,所以这些东西觉得现实用处没有那么大,然则对明白闭包对作用域链中的属性的援用,这一点照样有作用的。

8. 模块形式

指为单例建立私有变量和特权要领。所谓单例,指的是只要一个实例的对象。
如:

var application = function () {
  var components = []
  components.push(new BaseComponent()) // BaseComponent 指初始化组建
  return {
    getComponentCount: function () {
      return components.length
    },
    registerComponent: function (component) {
      if (typeof component === 'object') {
        components.push(component)
      }
    }
  }
}()

增强版,合适那种单例必需是某种范例的实例:

var application = function () {
  var components = []
  components.push(new BaseComponent())
  var app = new Base()
  app.getComponentCount = function () {
    return components.length
  }
  app.registerComponent = function (component) {
    if (typeof component === 'object') {
      components.push(component)
    }
  }
  return app
}()
// 函数表达式和闭包部份完毕
    原文作者:wfc_666
    原文地址: https://segmentfault.com/a/1190000007840164
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞