13.闭包作用域「*复看」

78 阅读4分钟

1

// 注意:由于现在都处于webpack编译,基于严格模式了,所以此种情况可不必再特别重视了
/**
 * EC(G)
 * vo
 *  a = 4
 *    
 *  b=0x000:scope:G
 * up
 *  var a
 *  b=0x000:scope:G
 */
var a = 4;
function b(x, y, a) {
  /**
   * EC(b)
   * ao
   *  x = 1
   *  y = 2
   *  a = 3
   *    = 10 // arguments映射修改
   * scope: b,G
   * 初始化arguments: 0x001
   * arg(形参赋值): x=1 y=2 z=3 
   * ---------------------
   * *注意:在JS的“非严格模式”下,初始完成agruments和形参赋值结束后
   *    + 会建立arguments和形参之间的映射机制「一一对应:如果存在映射机制,一个修改,另外一个也会跟着修改」
   *    + 只有在这个阶段才会建立映射机制,代码执行的时候,则不再处理这些事情了
   * ---------------------
   * 变量提升up:
   * 代码执行run:
   *  console.log(a);
   *    arguments[2] = 10;
   *    console.log(a);
   */
  
  console.log(a);
  arguments[2] = 10;
  console.log(a);
}
a = b(1, 2, 3);
console.log(a);

/**
 * 0x001
 * arguments 类数组对象 0x001
 * 0: 1
 * 1: 2
 * 2: 3
 * length: 3
 * callee: ...
 */
function fn(x, y, z) {
  // 初始arguments:{0:1,1:2,length:2}
  // 形参赋值:x=1 y=2 z=undefined // *注意:此处形参赋值时,z并没有建立映射机制
  // 「映射机制 ARG[0]:x ARG[1]:y」
  arguments[0] = 10
  console.log(x) // 10

  y = 20
  console.log(arguments[1]) // 20

  // 最开始没有建立起来映射机制,后期不论如何处理,都没有关系
  console.log(z) // undefined
  arguments[2] = 30
  console.log(z) // undefined
}

/*
10
20
undefined
undefined
*/

3

var a = 9;
function fn() {
    a = 0;
    return function (b) {
        return b + a++;
    }
}
var f = fn();
console.log(f(5));
console.log(fn()(5));
console.log(f(5));
console.log(a);
/**
 * EC(G)
 * vo:
 *  a
 *    = 9
 *    = 0
 *    = 1
 *    = 0
 *    = 1
 *    = 2
 *  fn = 0x000; scope = EC(G)
 *  f 
 *    = 0x001
 * up: var a,fn,var f
 */
var a = 9;
function fn() {
  /**
   * EC(fn1) 不释放
   * ao: -
   * scope: fn1,G
   * arg: -
   * up: -
   */
  /**
   * EC(fn2)
   * ao: -
   * scope: fn2,G
   * arg: -
   * up: -
   */
  a = 0;
  return function (b) {
    /**
     * EC(fn1c) 不释放
     * ao: -
     * scope: fn1c,fn1,G
     * arg: b = 5
     * up: -
     */
    /**
     * EC(fn2c)
     * ao: -
     * scope: fn1c,fn1,G
     * arg: b = 5
     * up: -
     */
    /**
     * EC(fn1c)
     * ao: -
     * scope: fn1c,fn1,G
     * arg: b = 5
     * up: -
     */
    return b + a++;
  }
}
var f = fn();
console.log(f(5)); // => 5
console.log(fn()(5)); // => 5
console.log(f(5)); // => 6
console.log(a); // => 2

4

var test = (function (i) {
    return function () {
        alert(i *= 2);
    }
})(2);
test(5);
/**
 * 把自执行函数执行的返回结果赋值给test
 */
/**
 * EC(G)
 * vo
 *  test
 *    = 0x0001:scope:an
 * up: var test
 */
var test = (function (i) {
  /**
   * EC(an) 不释放
   * ao: -
   *  i = 2
   *    = 4
   * scope:an,G
   * args: i=2
   * up: -
   */
  return function () {
    /**
     * EC(test)
     * ao: -
     * scope: test,an,G
     * arg: -
     */
    alert(i *= 2); // 让EC(an)中的i在自身基础上累成2 =》 4
  }
})(2);
test(5);

/*
alert(4)
*/

5

var x = 4;
function func() {
    return function(y) {
        console.log(y + (--x));
    }
}
var f = func(5);
f(6);
func(7)(8);
f(9);
console.log(x);
/**
 * EC(G)
 * vo:
 *  x = 4
 *    = 3
 *    = 2
 *    = 1
 *  func = 0x000;scope:G
 *  f = 0x0001
 * up: var x,func,f
 */
var x = 4;
function func() {
  /**
   * EC(func) 不释放
   * scope:func,G
   */
  return function (y) {
    /**
     * EC(funcc) 0x001不释放
     * ao
     *  y = 6
     * scope:funcc,func,G
     * arg:y
     */
    /**
     * EC(funcc2)
     * ao
     *  y = 8
     * scope:funcc,func,G
     * arg:y
     */
    /**
     * EC(funcc) 不释放
     * ao
     *  y = 9
     * scope:funcc,func,G
     * arg:y
     */
    console.log(y + (--x));
  }
}
var f = func(5);
f(6); // 9
func(7)(8); // 10
f(9); // 10
console.log(x); // 1

/*
9
10
10
1
*/

6.

var x = 5,
    y = 6;
function func() {
    x += y;
    func = function (y) {
        console.log(y + (--x));
    };
    console.log(x, y);
}
func(4);
func(3);
console.log(x, y);
/**
 * EC(G)
 * vo
 *  x = 5
 *    = 11
 *    = 10
 *  y = 6
 *  func = 0x000;scope:EC(G)
 * up: var x ,var y, func
 */
var x = 5,
  y = 6;
function func() {
  /**
   * EC(f1)
   * scope: f1,G
   */
  x += y; // 改变全局 x=11
  func = function (y) { // 「函数重构」全局的func=0x001;scope:f1
    /**
     * EC(f2)
     * scope:f2,f1
     * arg: y=3
     */
    console.log(y + (--x)); // => 13
  };
  console.log(x, y); // => 11 6
}
func(4);
func(3);
console.log(x, y); // 10 6

7 * 复看

/**
 * EC(G)
 * vo
 *  fun = 0x000
 *  c = 0x003
 * up: var c,fun
 */
function fun(n, o) {
  /**
   * EC(fn) 0x000(0)
   * ao
   *  n = 0
   *  o = undefined
   *    = 1
   * scope:fun,G
   * arg: n,o
   */
  /**
   * EC(fn) 0x000(0,1)
   * ao
   *  n = 0
   *  o = 1
   * scope:fun,G
   * arg: n,o
   * run:
   *  console.log(1)
   */
  /**
   * EC(fn) 0x000(0,1)
   * ao
   *  n = 0
   *  o = 1
   * scope:fun,G
   * arg: n,o
   * run:
   *  console.log(1)
   */
  console.log(o);
  return {
    // 0x001 临时不被释放
    // 0x003 闭包
    fun: function (m) {
      /**
       * EC(fnc) 0x002(1)
       * ao:
       *  m = 1
       * scope: func,fun
       * arg: m
       * run:
       *  0x000(1,0)
       */
      /**
       * EC(fnc) 0x004(2)
       * ao:
       *  m = 2
       * scope: func,fun
       * arg: m
       */
      return fun(m, n);
    }
  };
}
var c = fun(0).fun(1);
/**
 * undefined
 * 1
 */
c.fun(2);
/**
 * undefined
 * 1
 */
c.fun(3);

11

// 11 实现函数fn,让其具有如下功能(百度二面)
// let res = fn(1, 2)(3);
// console.log(res); //=>6  1+2+3

// *注意:node执行不行
// 方式一:
function add(...params) {
  const proxy = (...args) => {
    // 把每一次传递的信息都保存在原始的集合中
    params = params.concat(args)
    return proxy
  }
  // proxy.toString = () => {
  proxy.toString = () => {
    // 基于函数运算或者输出的时候,隐式调用函数的toString,我这里实现求和即可
    return params.reduce((result, item) => result + item)
  }
  return proxy
}

let res = add(1)(2)(3)
console.log(res) // -> 6

res = add(1, 2, 3)(4)
console.log(res) // -> 10

res = add(1)(2)(3)(4)(5)
console.log(res) // -> 15



// // 方式二:
// function curring() {
//   let params = [];
//   let add = function (...args) {
//     params = params.concat(args);
//     return add
//   }
//   add.toString = function () {
//     return params.reduce((result, item) => result + item)
//   }
//   return add
// }
// let add = curring()


// let res = add(1)(2)(3)
// console.log(res) // -> 6

// add = curring() // -> 执行前每次初始化params
// res = add(1, 2, 3)(4)
// console.log(res) // -> 10

// add = curring() // -> 执行前每次初始化params
// res = add(1)(2)(3)(4)(5)
// console.log(res) // -> 15