super-fool / blog

珍藏经典, 分享思想, 共同进步.加油
3 stars 0 forks source link

js-函数(作用域, this) #4

Open super-fool opened 5 years ago

super-fool commented 5 years ago

函数声明具有 declaration hoisting (声明提升), 函数表达式没有. var 声明变量 具有 variable hoisting(变量提升). let 没有.

看看以下的🌰:

console.log(b); // 这里的b是第二个函数。

function b(){
  console.log('call b first');
}

function b(){
  console.log('call b second');
}

var b = 'Hello World';

以上问题的原因是:函数提升要大于变量提升。

super-fool commented 5 years ago

var 具有函数作用域, let 具有的是 块级作用域:

🌰 1:

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function() {
    console.log(i);
  };
}
a[2](); //  ??

🌰 2;

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = () => console.log(i);
}
a[2](); //  ??

🌰 3:

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = () => console.log(i);
  a[i](); // ??
}

🌰 4:

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = () => console.log(i);
}
a[6](); // ??

🌰 1-2 比较:

普通函数和箭头函数在这里是没有区别的, 因为这里没有 this(执行上下文).

⚠️:

🌰 2-3 比较:

考点: 立即执行函数(IIFE)的.

🌰 2-4 比较:

考点: 函数作用域 var, 块级作用域 let.


由于 let 是 es6 的新增词法, 那么如何让 🌰4 实现 var 的  代码呢?

var a = [];
var _loop = function _loop(i) {
  return function() {
    console.log(i);
  };
};
for (var i = 0; i < 10; i++) {
  a[i] = _loop(i);
}
a[3](); // ??
super-fool commented 5 years ago

🌰

var test = {
    _name: 'Chicago Bulls',
    tellName() {
        console.log(this._name);
    },
    tellAliasName: function() {
        return ()=>{
            console.log(this._name);
        }
    }
}

var outer = {
    __proto__: test,
    alias: test,
    aliasName:test.tellAliasName(),
    _name: 'lrving'
}

outer.tellName(); // 谁调用,this就指向谁. ‘lrving'
outer.tellAliasName()(); // 箭头函数的父函数的上下文(即谁调用, 就是谁)是谁, this就是谁.  ‘Lrving'
outer.alias.tellName(); // 'Bulls'
outer.alias.tellAliasName();// 'Bulls'
outer.aliasName(); // 'Bulls'
super-fool commented 5 years ago
for (let i = 0 /* 作用域a */; i < 3; console.log("in for expression", i), i++) {
  let i; //这里没有报错,就意味着这里跟作用域a不同
  console.log("in for block i: ", i);
  console.log("in for block k: ", k);
}

我们改造一下, 在 for 中, 我们可以把 let i = 0提出来试一下.

{
  let i = 0;
  for (i < 3; console.log("in for expression", i); i++) {
    let k = i, i; //这里添加了一个K, 并且精简了下.
    console.log("in for block i: ", i);
    console.log("in for block k: ", k);
  }
}

哦吼, 报错了...排查一下问题...🔍

首先, 看下 for 语句:
for(语句1; 语句2; 语句3)
语句 1(代码块)开始前执行
语句 2 定义运行循环(代码块)的条件
语句 3 在循环(代码块)已被执行之后执行

我们发现语句2就已经写错了, 那我们改一下:

{
  let i = 0;
  for (;i < 3; console.log("in for expression", i), i++) {
    let k = i,
      i; //这里精简了下.
    console.log("in for block i: ", i);
    console.log("in for block k: ", k);
  }
}

这时候又报了另一个问题: i is not defined; 这又是一个基础问题: let k = i, i;. 这里声明赋值的顺序是从右至左. 所以还得改一下.

{
  let i = 0;
  for (;i < 3; console.log("in for expression", i), i++) {
    let i, k = i; //这里精简了下.
    console.log("in for block i: ", i);
    console.log("in for block k: ", k);
  }
}