【ES6】ES6中的作用域

1. window全局作用域 全局变量

var abc = 123;
bcd = 234;
// var 定义的这个abc肯定是全局变量。  且是挂在window下面的。    window.abc可以访问到
// bcd不直接定义,也是挂在在window下,可以访问到。 window.bcd       window是个全局对象。
// 区别,bcd不能说是变量,只能说是window的属性;  变量不能删除,属性可以删除
delete abc;    // false     也可以是 delete window.abc   变量,不能被删除,还是可以访问。
delete bcd;    // true      也可以是 delete window.bcd   删除了,访问不到

var abc = 123;
// 这个全局变量,可以在整个文件访问到。  例如:index.html 里引入 1.js 和 2.js。  其中1.js里面定义了var abc。 那么2.js也可以访问到

// 函数内部没有var定义的变量,不具备函数作用域,是全局作用域下
function test1(){
    ab = 45;     // 函数执行之后,这个变量可以在全局都访问到
    delete ab;   // true   这个和上面bcd一样,相当于window的属性。不是变量
    ab = 35;
}
test1();

2. 函数作用域 局部作用域

function test2() {
    var a = 3;
    if(a === 3){
        var b = 4;  // var只有函数作用域与全局作用域。 if后面的{}是块状作用域,var没法封锁块级作用域
        let c = 5;  // let可以在当前块级作用域下封锁,块级作用域以外访问不到c
        console.log('aaa');
    }else{
        console.log('bbb')
    }
    console.log(b);   // 4
    console.log(c);   // 报错 拿不到c
    return a + 4;
}
console.log(test2());  // 7
console.log(a);        // 报错 不能拿到a

3. 动态作用域

a = 3;
function test() {
    var a = 5;
    console.log(this.a);
    console.log(a);   // 5
}
test();  // 3   5     此时test里面的this指向的是当前函数所处的环境。此时就是全局window
test.bind( {a: 100} )();  // 100  5    bind改变了test里面this的指向。指向了一个新的对象。 这个对象里面a=100

4. 作用域链的理解

对于一个变量,引擎从当前作用域开始查找变量,如果找不到,就会向上一级继续查找。当抵达最外层全局作用域时,无论找到还是没有找到,查找过程中都会停止。
例子:

for(var i = 0; i < 3; i++){
    setTimeout(function () {
        console.log(i);
    }, 1000)
}
// 最后结果,会一次输出3个i。  i当前的作用域是全局。 setTimeout里面,i会向上去找,向上没有函数作用域,直接就找到了全局。 此时,i已经执行完了循环,i=3。
for(let i = 0; i < 3; i++){
    setTimeout(function () {
        console.log(i);
    }, 1000)
}
// 1s之后,会按顺序一次性输出0 1 2。   因为let把当前的i限制在for这个块级作用域下。 setTimeout访问时只会到当前所处的for循环体里去找i

再看一个例子

var liList = document.querySelectorAll('li') // 共5个li
for(var i=0; i<liList.length; i++){
    liList[i].onclick = function(){
        console.log(i)
    }
}
// var声明i  每个li点击后 都是弹出5。
var liList = document.querySelectorAll('li') // 共5个li
for(var i=0; i<liList.length; i++){
    liList[i].onclick = function(){
        console.log(i)
    }
}
// let声明i  每个i可以顺利的打印出 0 1 2 3 4

解释:

  1. i的声明被提升。
  2. 当运行for循环时为i赋值,并为每个li绑定事件(注意:运行for循环时只是绑定了事件但是并没有执行事件)。
  3. 当触发事件时(注意:此时for循环执行完了),现在需要控制台打印i的值,于是i便沿着作用域链寻找它的值。
  4. 当用var声明时,i会在全局作用域中找到它的值,为5.
  5. 当用let声明时,i会在for的第一行找到它的值,每次的值不一样,分别为0、1、2、3、4.

同理,再看一个问题:
Question: 生成十个按钮,每个点击的时候弹出1 - 10

// 利用自运行函数,可以成功。
var i = 0;
for (i = 1; i <= 10; i++) {
    // 一个自运行的函数 (function (i))(i)       相当于(function (i))(1)   (function (i))(2)   (function (i))(3) ...
    // 这个函数里面的i是独立的作用域,是最后(i)传进来的
    (function (i) {
        var btn = document.createElement('button');
        btn.innerText = i;
        btn.onclick = function () {
            alert(i);
        };
        document.body.appendChild(btn);
    })(i)
}

// 去掉自运行的函数,结果会生成1-10个按钮,但是弹出来的永远是11
var i = 0;
for (i = 1; i <= 10; i++) {
    var btn = document.createElement('button');
    // 这个i会遵循1-10的循环,所以生成按钮内容都是1-10
    btn.innerText = i;
    //  这里的i并不参与循环,相当于给每个按钮绑定一个事件。此时alert里面的值没确定。每次点击按钮的时候,alert(i)就会向上去找i,此时i已经结束循环了,变成11
    btn.onclick = function () {
        alert(i);
    };
    document.body.appendChild(btn);
}

// 用let就和其他java等语言一样,这个i只作用于当前for循环的作用域内,不需要自运行函数
for (let i = 1; i <= 10; i++) {
    var btn = document.createElement('button');
    btn.innerText = i;
    btn.onclick = function () {
        alert(i);
    };
    document.body.appendChild(btn);
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值