面试题:请讲一下闭包

作用域

要理解闭包,首先要理解变量的作用域。作用域分为全局作用域和函数作用域(ES5)。在作用域链上,函数内部可以获取外部的变量,但是函数外部不能获取函数内部的变量。

闭包就是可以在函数外部获取内部变量的一种方法。

闭包最大的特点就是可以记住他所诞生的环境,本质是链接函数内外部。

闭包的用途

  1. 读取函数内部的变量,这些变量始终在内存中(因为引用关系一直存在)。-----所以在不用变量之后需要手动释放变量。

  2. 能够封装对象的私有属性和方法

注意

  1. 因使用闭包使函数中的变量始终在内存中,内存消耗大,所以不能滥用,否则会造成页面的性能问题,在ie中可能会导致内存泄露。

  2. 如果用封装的话,不要任意修改私有属性。

闭包形成的三个条件

  1. 函数嵌套

  2. 访问所在的作用域的函数

  3. 在所在作用域外被调用

闭包的十种表示方式

  1. 返回值

这是一种最常见的表现形式。

var fn = function(){
  var name = 'nxl'
  return function(){
    return name
  }
}()
console.log(fn())
  1. 函数赋值

将内部函数赋值给一个外部的对象。

var fn2;
var fn = function() {
  var name = 'nxl'
  var a = function(){
    return name
  }
  fn2 = a
}
fn()
console.log(fn2())

  1. 函数参数

把函数当作参数传给另一个函数。

function fn2(f){
  console.log(f())
}
function fn() {
  var name = 'nxl'
  var a = function() {
    return name
  }
  fn2(a)
}
fn()
  1. IIFE
function fn2(f){
  console.log(f())
}
(function(){
  var name = 'nxl'
  var a = function() {
    return name
  }
  fn2(a)
})()
  1. 循环赋值
function foo(){
  var arr = []
  for(var i = 0; i< 10; i++) {
    arr[i] = (function(n){
      return function(){
        return n
      }
    })(i)
  }
  return arr
}
var bar = foo()
console.log(bar[3]())
  1. gettersetter
var getValue, setValue

(function() {
  var num = 0
  getValue = function() {
    return num
  }
  setValue = function(n) {
    if(typeof n === 'number') {
      num = n
    }
  }
})()
console.log(getValue())
setValue(10)
console.log(getValue())
  1. 迭代器

计数器

var add = function() {
  var num = 0
  return function() {
    return ++num
  }
}()
console.log(add())
console.log(add())
console.log(add())

迭代数组

function setUp(arr) {
  var i = 0
  return function() {
    return arr[i++]
  }
}
var next = setUp(['1', '2', '3', '4'])
console.log(next())
console.log(next())
console.log(next())
console.log(next())
  1. 区分首次
var firstLoad = (function(){
  var list = []
  return function(id) {
    if(list.indexOf(id) >= 0) {
      return false
    } else {
      list.push(id)
      return true
    }
  }
})()
console.log(firstLoad(10))
console.log(firstLoad(10))
  1. 缓存机制
// 未加入缓存
function mult() {
  var sum = 0
  for(var i = 0; i < arguments.length; i++) {
    sum += arguments[i]
  }
  return sum
}
console.log(mult(1,2,3,5,3,2,3))
console.log(mult(1,2,3,5,3,2,3))
// 加入缓存
var mult = function() {
  var cache = {}
  var calculate = function() {
    var sum = 0
    for(var i = 0; i< arguments.length; i++) {
      sum += arguments[i]
    }
    return sum
  }
  return function() {
    var args = Array.prototype.join.call(args, ',')
    if(args in cache) {
      return cache[args]
    } else {
      return cache[args] = calculate.apply(null, arguments)
    }
  }
}

console.log(mult(1,2,3,5,3,2,3))
console.log(mult(1,2,3,5,3,2,3))

  1. img图片上传
// 低版本浏览器在进行数据上报,会丢失30%左右的数据
var report = function(src) {
  var img = new Image()
  img.src = src
}
report('http://xxx.com/getUserInfo')
// 用闭包来做图片上传
var report = function(src) {
  var imgs = []
  return function(src) {
    var img = new Image()
    imgs.push(img)
    img.src = src
  }
}
report('http://xxx.com/getUserInfo')

关于闭包的练习题

  • example 1
function funA() {
  var a = 10
  return function () {
    console.log(a)
  }
}
var b = funA()
b()
  • example 2
function outerFn() {
  var i = 0
  function innerFn() {
    i++
    console.log(i)
  }
  return innerFn
}
var inner = outerFn()
inner()
inner()
inner()
var inner2 = outerFn()
inner2()
inner2()
inner2()
  • example 3
var i = 0
function outerFn() {
  function innerFn() {
    i++
    console.log(i)
  }
  return innerFn
}
var inner1 = outerFn()
var inner2 = outerFn()
inner1()
inner2()
inner1()
inner2()
  • example 4
function fn() {
  var a = 3
  return function () {
    return ++a
  }
}
console.log(fn()());
console.log(fn()());
var newFn = fn()
console.log(newFn())
console.log(newFn())
console.log(newFn())
  • example 5
function outerFn() {
  var i = 0
  function innerFn() {
    i++
    console.log(i);
  }
  return innerFn
}
var inner1 = outerFn()
var inner2 = outerFn()
inner1()
inner2()
inner1()
inner2()
  • example 6
  (function () {
    var m = 0
    function getM() { return m }
    function setA(val) { m = val }
    window.g = getM
    window.f = setA
  })()
f(100)
console.info(g());
  • example 7
function a() {
  var i = 0
  function b() { console.log(++i) }
  return b
}
var c = a()
c()
c()
  • example 8
function f() {
  var count = 0
  return function () {
    count++
    console.info(count);
  }
}
var t1 = f()
t1()
t1()
t1()
  • example 9
var add = function (x) { // x=1
  var sum = 1
  var tmp = function (x) { //x=2  x=3
    sum = sum + x // 3 6
    return tmp
  }
  tmp.toString = function () {
    return sum
  }
  return tmp
}
console.log(add(1)(2))
console.log(add(1)(2)(3))
  • example 10
var lis = document.getElementsByTagName('li')
for (var i = 0; i < lis.length; i++) {
  (function (i) {
    lis[i].onclick = function () {
      console.log(i);
    }
  })(i) //  //事件处理函数中闭包的写法
}
  • example 11
function m1() {
  var x = 1
  return function () {
    console.log(++x);
  }
}
m1()()
m1()()
m1()()
var m2 = m1()
m2()
m2()
m2()
  • example 12
var fn = (function () {
  var i = 10
  function fn() {
    console.log(++i);
  }
  return fn
})()
fn()
fn()
  • example 13
function love1() {
  var num = 223
  var me1 = function () {
    console.log(num);
  }
  num++
  return me1
}
var loveme1 = love1()
loveme1()
loveme1()
  • example 14
function fun(n, o) {
  console.log(o);
  return {
    fun: function (m) {
      return fun(m, n)
    }
  }
}
var a = fun(0)
a.fun(1) // 执行fun(1,0)
a.fun(2) // 执行fun(2,0)
a.fun(3) // 执行fun(3,0)
var b = fun(0).fun(1).fun(2).fun(3)
// 1 fun(0)----------// n=0 o=undefined 打印undefined 返回fun(m,0)函数
// 2 fun(0).fun(1)---------- // 执行fun(1,0) n=1 o=0 打印0 返回fun(m,1)
// 3 fun(0).fun(1).fun(2)---------- // 执行fun(2,0) n=2 o=1 打印1 返回fun(m, 2)
// 3 fun(0).fun(1).fun(2).fun(3)---------- // 执行fun(3,0)  n=3 o=2  打印2返回fun(m, 2)
var c = fun(0).fun(1) // 执行fun(1,0) n=1 o=0 打印undefined 0 返回fun(m,1)
c.fun(2) // 执行fun(2,1) n=2 o=1 打印1 返回fun(m,2)
c.fun(3) // 执行fun(3,1) n=3 o=1 打印1 返回fun(m,3)
  • example 15
function fn() {
  var arr = [];
  for (var i = 0; i < 5; i++) {
    // (function (i) {
    arr[i] = function () {
      return i;
    }
    // })(i)
  }
  return arr;
}
var list = fn();
for (var i = 0, len = list.length; i < len; i++) {
  console.log(list[i]());
}
  • example 16
function fn() {
  var arr = [];
  for (var i = 0; i < 5; i++) {
    arr[i] = (function (i) {
      return function () {
        return i;
      };
    })(i);
  }
  return arr;
}
var list = fn();
for (var i = 0, len = list.length; i < len; i++) {
  console.log(list[i]());
}

参考:
深入理解闭包(视频)
学习Javascript闭包(Closure)
JS 中的闭包是什么?
闭包,看这一篇就够了——带你看透闭包的本质,百发百中
MDN闭包

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值