ES6中var let const的区别以及箭头函数

1. var let const的区别

随着ES6规范的到来,Js中定义变量的方法已经由单一的 var 方式发展到了 var、let、const 三种之多。

下文来讨论下这三种方式的区别

1.1 Js没有块级作用域

请看这样一条规则:在JS函数中的var声明,其作用域是函数体的全部

for(var i=0;i<10;i++){
     var a = 'a';
}

console.log(a);

跳出了循环的变量a和i,在循环外能被访问到。

首先解释一下变量提升:

JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)。

这就导致了var声明的变量没有块级作用域。

1.2 循环内变量过度共享

for (var i = 0; i < 3; i++) {
    setTimeout(function () {
      console.log(i)
    }, 1000);
}

输出结果为3,3,3而不是0,1,2。循环本身及三次 timeout 回调均共享唯一的变量 i 。当循环结束执行时,i 的值为3。所以当第一个 timeout 执行时,调用的 i 当让也为 3 了。

1.3 let与const

ES6中let解决了上面var的问题,其特点概括如下:

  • let声明的变量拥有块级作用域。 也就是说用let声明的变量的作用域只是外层块,而不是整个外层函数。let 声明仍然保留了提升特性,但不会盲目提升,在示例一中,通过将var替换为let可以快速修复问题,如果你处处使用let进行声明,就不会遇到类似的bug。
  • let声明的全局变量不是全局对象的属性。这就意味着,你不可以通过window.变量名的方式访问这些变量。它们只存在于一个不可见的块的作用域中,这个块理论上是Web页面中运行的所有JS代码的外层块。
  • 形如for (let x...)的循环在每次迭代时都为x创建新的绑定。
    这是一个非常微妙的区别,拿示例二来说,如果一个for (let...)循环执行多次并且循环保持了一个闭包,那么每个闭包将捕捉一个循环变量的不同值作为副本,而不是所有闭包都捕捉循环变量的同一个值。
    所以示例二中,也以通过将var替换为let修复bug。
    这种情况适用于现有的三种循环方式:for-of、for-in、以及传统的用分号分隔的类C循环。
  • 用let重定义变量会抛出一个语法错误(SyntaxError)。这个很好理解,用代码说话
    let a = 'a';
    let a = 'b';
    上述写法是不允许的,浏览器会报错,因为重复定义了。

const更好理解,可以想象成Java中的final(不过,const 关键字并不会限制对 object 的修改),这里不多做阐述了。

经验阐述:能用 const 尽量用 const,不要轻易的 mutate object,代码结构复杂后会有好处。

2. 箭头函数

ES6标准新增了一种新的函数:Arrow Function(箭头函数)。

x => x * x

上面的箭头函数相当于:

function (x) {
    return x * x;
}

箭头函数相当于匿名函数(

(function(){...})();

),并且简化了函数定义。箭头函数有两种格式,一种像上面的,只包含一个表达式,连{ ... }return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ ... }return

x => {
    if (x > 0) {
        return x * x;
    }
    else {
        return - x * x;
    }
}

如果参数不是一个,就需要用括号()括起来:

// 两个参数:
(x, y) => x * x + y * y

// 无参数:
() => 3.14

// 可变参数:
(x, y, ...rest) => {
    var i, sum = x + y;
    for (i=0; i<rest.length; i++) {
        sum += rest[i];
    }
    return sum;
}

如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:

// SyntaxError:
x => { foo: x }

因为和函数体的{ ... }有语法冲突,所以要改为:

// ok:
x => ({ foo: x })

2.1 this

箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。

回顾前面的例子,由于JavaScript函数对this绑定的错误处理,下面的例子无法得到预期结果:

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = function () {
            return new Date().getFullYear() - this.birth; // this指向window或undefined
        };
        return fn();
    }
};

现在,箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
        return fn();
    }
};
obj.getAge(); // 25

如果使用箭头函数,以前的那种hack写法:

var that = this;

就不再需要了。

由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略:

var obj = {
    birth: 1990,
    getAge: function (year) {
        var b = this.birth; // 1990
        var fn = (y) => y - this.birth; // this.birth仍是1990
        return fn.call({birth:2000}, year);
    }
};
obj.getAge(2015); // 25

3. call & apply

call和apply作用很相似,函数执行时,在某个指定作用域下调用。只是参数的写法不同,

call(this,arg1,arg2..)
apply(this.argunments)

比如

obj1.method1.call(obj2,argument1,argument2) 

call的作用就是把obj1的方法放到obj2上使用,后面的argument1..这些做为参数传入。 

function add(a,b) 
{ 
    alert(a+b); 
} 
function sub(a,b) 
{ 
    alert(a-b); 
} 
add.call(sub,3,1); 

上述代码的意思就是用add来替换sub,add.call(sub,3,1) == add(3,1) ,所以运行结果为:alert(4); // 注意:js 中的函数其实是对象,函数名是对 Function 对象的引用。 

 

 

Reference:

1. http://www.jianshu.com/p/4e9cd99ecbf5

2. http://www.cnblogs.com/52fhy/p/5117267.html

3. https://www.zhihu.com/question/34294629?sort=created

4. http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001438565969057627e5435793645b7acaee3b6869d1374000

5. http://www.cnblogs.com/sweting/archive/2009/12/21/1629204.html

转载于:https://my.oschina.net/hosee/blog/906960

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值