es6改进es5中的一些坑

来源:互联网 发布:软件升级管理 编辑:程序博客网 时间:2024/05/17 09:18

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());// NaNconsole.log(add(true));// 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注意,为什么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));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

使用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());// 30console.log(add(true));// 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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

var arr = [];for (var i = 0; i < 3; i++) {// i 是全局变量    arr.push(function () {        return i;    });}console.log(i); // 3, 由此可见i为全局变量// arr中保持的三个函数的返回值均是全局变量ifor (var j = 0; j < 3; j++) {    console.log(arr[j]()); // 3 3 and 3}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

如果不使用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}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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

var arr = [];for (let i = 0; i < 3; i++) {    arr.push(function () {        return i; // 局部变量    });}console.log(i); // error, 在全局中找不到变量ifor (var j = 0; j < 3; j++) {    console.log(arr[j]()); // return 0, 1, 2}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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()); // jianyongleep.getNameInCallback(); // undefined
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

注意到最后的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()); // jianyongleep.getNameInCallback(); // jianyong lee
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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()); // jianyongleep.getNameInCallback(); // jianyong lee
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

如果使用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
原创粉丝点击