ES6入门(一)

var声明及变量提升机制

在函数作用域或全局作用域中通过关键字var声明的变量,无论实际上是在哪里声明的,都会被当成在当前作用域顶部声明的变量,这就是我们常说的变量提升。

function getValue(condition) {
    if(condition){
        value = "blue";
        // 其他代码
        return value
    }else{
        // 此处可访问变量value,其值为undefined
        return null
    }
    // 此处可访问变量value,其值为undefined
}
复制代码

如果,你有其他编程语言的经验,例如Java,Python,Perl等,很可能会认为只有当condition的值为true时才会创建变量value。事实上,在预编译阶段,JavaScript引擎会将上面的getValue函数修改成下面这样:

function getValue(condition) {
    var value;
    if(condition){
        value = "blue";
        // 其他代码
        return value
    }else{
        // 此处可访问变量value,其值为undefined
        return null
    }
    // 此处可访问变量value,其值为undefined
}
复制代码

变量value的声明被提升至函数顶部,而初始化操作依旧在原地执行,所以在else子句中也可以访问到value变量,只不过值为undefined,因为尚未初始化。

块级声明

ES6中为了解决变量提升给开发者带来的困扰,所以特地引入了块级作用域来强化对变量生命周期的控制。

块级作用域也被称为词法作用域,存在于

  • 函数内部
  • 块中({}之间的区域)

let声明

let与var的用法相同,区别是,用let声明的变量的作用域被限制在当前的代码块中。所以let声明的变量不存在变量提升。

function getValue(condition) {
    if(condition){
        let value = "blue";
        // 其他代码
        return value
    }else{
        // 变量value在此处不存在
        return null
    }
    // 变量value在此处不存在
}
复制代码

改为let声明后,如果condition的值为false,value就不会存在

禁止重复声明

var value = 10
// 抛出语法错误
let value = 20
复制代码

同一作用域中,不能用let重复定义已经存在的标识符,不然会报错。 但如果当前作用域内嵌另一个作用域,便可用let声明同名变量

var value = 10
if(condition){
    // 不会抛出错误
    let value = 20
    // 其他代码
}
复制代码

注意:这里if内部的value会遮蔽if外部的value,后者只有在if块外才能访问到。

const 声明

ES6中提供了const关键字。使用const声明的是常量,意味着,其值一旦设定,不可更改。所以使用const声明常量时,一定要在声明时就进行初始化操作。

// 有效的常量
const MAX = 10;
// 语法错误:常量未初始化
const MIN;
复制代码

const和let声明的变量都是块级标识符,所以都是只在当前代码块内有效,一旦执行到块外会被销毁。

if(condition){
    const MAX = 10;
    // 其他代码
}
// 此处无法访问MAX变量
复制代码

与let相似,在同一一作用域使用const重复声明已经存在的变量也会导致语法错误。

var name = "小米";
let age = 18

// 这两条语句都会抛出错误
const name = "大米";
const age = 25
复制代码

用const声明对象

通常来说,const声明不允许修改绑定,但允许修改值,也就是说用const声明对象可以修改对象的属性值,但是不能修改对象的引用。

const person = {
    name: "小米",
    age: 18
}

// 可以修改对象的属性值
person.name = "大米"
// 抛出语法错误
person = {
    name: "大米"
}
复制代码

我们知道,let和const声明的变量不存在变量提升,所以如果在变量声明之前访问该变量,会报错。

if(condition){
    console.log(typeof value); // 引用错误
    let value = "blue"
}
复制代码

循环中的块作用域绑定

for(var i = 0; i < 9; i++){
    console.log(arr[i])
}
// 在这里仍然可以访问变量i
console.log(i); // 9
复制代码

如果想变量i只存在于for循环中,可以使用let变量

for(let i = 0; i < 9; i++){
    console.log(arr[i])
}
// i在这里不可以访问,会报错
console.log(i); // 9
复制代码

循环中的函数

我们在开发中经常会遇到以下问题

var funcs = [];
for(var i = 0; i < 10; i++){
    funcs.push(function(){
       console.log(i); 
    })
}
funcs.forEach(function(func){
    func(); // 输出10次数字10
})
复制代码

为了解决这个问题,通常会使用立即调用函数表达式。

var funcs = [];
for(var i = 0; i < 10; i++){
    funcs.push((function (value) {
        return function () {
            console.log(value)
        }
    }(i)))
}

funcs.forEach(function (func) {
    func(); // 输出0,然后是1,2,直到9
})
复制代码

ES6出现之后,可以直接使用let声明变量来简化上述过程

var funcs = [];
for(let i = 0; i < 10; i++){
    funcs.push(function(){
       console.log(i); 
    })
}
funcs.forEach(function(func){
    func(); // // 输出0,然后是1,2,直到9
})
复制代码

全局块作用域绑定

let和const与var的另一个不同是,当var在全局作用域中声明一个变量时,它同时也会作为window对象的属性,这意味着,很可能会覆盖window对象中已经存在的属性。

// 在浏览器中
var RegExp = "Hello";
console.log(window.RegExp); // Hello

var a = 1;
console.log(window.a); // 1
复制代码

当let或者const在全局作用域中声明变量时,并不会作为window对象的属性。

// 在浏览器中
let RegExp = "Hello";
console.log(RegExp); // Hello
console.log(window.RegExp === RegExp); // false

const a = 1
console.log(a); // 1
console.log(a === window.a); // false
复制代码

块级绑定最佳实践的进化

默认使用const,只有需要改变变量的值时,才使用let

小结

let和const声明的变量具有块级作用域,不存在变量提升,在变量声明前使用,会导致暂时性死区,只可以在声明的代码块中使用。

猜你喜欢

转载自blog.csdn.net/weixin_33853794/article/details/91389364
今日推荐