es6改进es5中的一些坑

1. 块级作用域

es5中有一个比较坑的地方就是变量提升(variable hoisting),variable hoisting的根本原因就是es5中没有块级作用域。看一下下面的代码:

var a = 10;
var b = 20;
function add(flag) {
    if (flag) {
        var b = 10;
        return a + b;
    }
    return a + b;

}

console.log(add());// NaN
console.log(add(true));// 20

注意,为什么add()没有输出结果呢?因为变量提升。上面代码中,var b = 10定义在if中,由于es5没有块级作用域(函数体是es5中仅有的作用域块),所以变量b相当于在函数内部重新声明了一次,类似下面代码:

var a = 10;
var b = 20;
function add(flag) {
    var b; // undefined
    if (flag) {
        b = 10;
        return a + b;
    }
    return a + b; // if flag flase, then b is undefined

}

console.log(add());
console.log(add(true));

使用es6中的let关键字,就没有这么恶心了:

var a = 10;
var b = 20;
function add(flag) {
    if (flag) {
        let b = 10;
        return a + b;
    }
    return a + b;

}

console.log(add());// 30
console.log(add(true));// 20

值得一提的是,在for循环中使用var来定义变量,也会遇到变量提升的坑:

var arr = [];
for (var i = 0; i < 3; i++) {// i 是全局变量
    arr.push(function () {
        return i;
    });
}

console.log(i); // 3, 由此可见i为全局变量

// arr中保持的三个函数的返回值均是全局变量i
for (var j = 0; j < 3; j++) {
    console.log(arr[j]()); // 3 3 and 3
}

如果不使用es6中的let,需要使用javascript中的闭包来救火了:

var arr = [];
for (var i = 0; i < 3; i++) {
    (function (i) {

        arr.push(function () {
            return i; // 局部变量
        });
    })(i);
}

console.log(i); 

for (var j = 0; j < 3; j++) {
    console.log(arr[j]()); // return 0, 1, 2
}

使用es6,在for循环中使用let定义变量:

var arr = [];
for (let i = 0; i < 3; i++) {
    arr.push(function () {
        return i; // 局部变量
    });
}

console.log(i); // error, 在全局中找不到变量i

for (var j = 0; j < 3; j++) {
    console.log(arr[j]()); // return 0, 1, 2
}

2. 箭头函数

在es5中,this关键字像幽灵一般跳来跳去,不同的场景下this指向的对象不同。常见的坑是在回调函数中使用thisthis会脱离当前对象的上下文,而指向全局变量window对象。看下面掉进坑的代码:

function Person(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;

}

Person.prototype.getName = function () {
    return this.firstname + this.lastname;
}

Person.prototype.getNameInCallback = function () {
    setTimeout(function () {
        console.log(this.firstname, this.lastname);
    }, 1000);
}

var p = new Person('jianyong', 'lee');
console.log(p.getName()); // jianyonglee
p.getNameInCallback(); // undefined

注意到最后的p.getNameInCallback()输出undefined。这个问题如何解决呢?如果不是使用es6来救火的话,可以考虑使用下面两个技巧:
1. 使用bind()函数,为回调函数绑定上下文:

function Person(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;

}

Person.prototype.getName = function () {
    return this.firstname + this.lastname;
}

Person.prototype.getNameInCallback = function () {
    setTimeout(function () {
        console.log(this.firstname, this.lastname);
    }.bind(this), 1000);
}

var p = new Person('jianyong', 'lee');
console.log(p.getName()); // jianyonglee
p.getNameInCallback(); // jianyong lee

2.使用其他变量代理this

function Person(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;

}

Person.prototype.getName = function () {
    return this.firstname + this.lastname;
}

Person.prototype.getNameInCallback = function () {
        var ctx = this; // 用ctx变量记录当前对象
    setTimeout(function () {
        console.log(ctx.firstname, ctx.lastname); // 这里使用ctx
    }, 1000);
}

var p = new Person('jianyong', 'lee');
console.log(p.getName()); // jianyonglee
p.getNameInCallback(); // jianyong lee

如果使用es6中的箭头函数就没这么多事:

function Person(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;

}

Person.prototype.getName = function () {
    return this.firstname + this.lastname;
}

Person.prototype.getNameInCallback = function () {
    setTimeout(() => {
        console.log(this.firstname, this.lastname);
    }, 1000);
}

var p = new Person('jianyong', 'lee');
console.log(p.getName());
p.getNameInCallback();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值