软件开发的家园,编程爱好者的天地.

现在是:北京时间 2016/4/14 上午11:50:51 星期四

设为首页  |  加入收藏  |  网站地图

javascript es6改进es5中的一些坑
发布于:第八基地 来源:互联网 作者:天堂路上 时间:2017-10-19 点击:257

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指向的对象不同。常见的坑是在回调函数中使用this,this会脱离当前对象的上下文,而指向全局变量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)
0%
对我没帮助
(0)
0%
返回顶部
在线反馈
在线反馈