ECMAScript6 [一]

Home文章
 简介:了解块级作用域,使用let 和 const

本文英文版地址:https://leanpub.com/understandinges6/read/#leanpub-auto-who-this-book-is-for

发现一本免费的电子书,还是鼎鼎大名的Nicholas C. Zakas写的,so......小翻译下

变量声明与提前

过去的用var声明函数会默认置顶,

function getValue(condition) {

    if (condition) {
        var value = "blue";

        // other code

        return value;
    } else {

        // value exists here with a value of undefined

        return null;
    }

    // value exists here with a value of undefined
}

 

如果你没用过js可能会认为只有congdition为true时value才会被赋值,实际上无论condition为何值,value都会存在。

有时这种行为会为我们带来很多隐藏的问题。

块级声明

let声明

let的语法和var一样,你基本可以用let替代var,只有几点细微的差别

  1. 变量作用域只在当前块中(花括号)
  2. 声明不会提前
  3. 不能够被重复声明
var count = 30;

// Syntax error
let count = 40;

如果一个变量已经存在了,那么再次用let则会报错。如果let在其自己的作用域内声明则不会有问题,例如

var count = 30;

// Does not throw an error
if (condition) {

    let count = 40;

    // more code
}

在上面这个例子中,let声明会覆盖(shadow)外层声明,直到if的块级作用域执行完。

const声明

在ECMAScript 6里还可以用const声明,但是是不能被重置或修改的;基于这个特性声明必须初始化时给一个值,否则会报错。

/ Valid constant
const maxItems = 30;

// Syntax error: missing initialization
const name;

 

const和let的区别

const只不能被修改,隐式声明和const冲突也会报错,无论严格模式和非严格模式。

const maxItems = 5;

maxItems = 6;      // throws error

const声明一个对象

const声明的另一个特性是如果声明的是对象的话,其属性值是可以改变的,略有奇怪不过记住就好了,例如

const person = {
    name: "Nicholas"
};

// works
person.name = "Greg";

// throws an error
person = {
    name: "Greg"
};

 

 

变量的周期(The Temporal Dead Zone

无论是let还是const,只有声明后才能访问,否则会报错,即便用一些类似typeof 比较保险的函数也不行

if (condition) {
    console.log(typeof value);  // ReferenceError!
    let value = "blue";
}

但是在块的外面就不会有这个问题

console.log(typeof value);     // "undefined"

if (condition) {
    let value = "blue";
}

循环中的块级作用域

js开发一直想for循环有个块级作用域,内部变量外部不可见,例如常用的一次性计数变量。

for (var i = 0; i < 10; i++) {
    process(items[i]);
}

// i is still accessible here
console.log(i);                     // 10

那么let可以帮你实现

for (let i = 0; i < 10; i++) {
    process(items[i]);
}

// i is not accessible here - throws an error
console.log(i);

循环中的函数

用var在循环中声明很麻烦,因为循环中定义的变量会被外部访问。

var funcs = [];

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

funcs.forEach(function(func) {
    func();     // outputs the number "10" ten times
});

你的初衷应该是打印0-9,但结果却是打印了10次‘10’,这是因为i已经被共享了,函数调用是i全部为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();     // outputs 0, then 1, then 2, up to 9
});

或者使用let

var funcs = [];

for (let i = 0; i < 10; i++) {
    funcs.push(function() {
        console.log(i);
    });
}

funcs.forEach(function(func) {
    func();     // outputs 0, then 1, then 2, up to 9
})

 

循环中的const

for 循环中const会报错,但是对象的话没关系

var funcs = [];

// throws an error after one iteration
for (const i = 0; i < 10; i++) {
    funcs.push(function() {
        console.log(i);
    });
}
//-------------------------
var funcs = [],
    object = {
        a: true,
        b: true,
        c: true
    };

// doesn't cause an error
for (const key in object) {
    funcs.push(function() {
        console.log(key);
    });
}

funcs.forEach(function(func) {
    func();     // outputs "a", then "b", then "c"
});

 

全局变量

用var声明全局变量会是全局对象的一个属性(window in browsers),这意味着你不小心的话可以覆盖全局属性。

// in a browser
var RegExp = "Hello!";
console.log(window.RegExp);     // "Hello!"

var ncz = "Hi!";
console.log(window.ncz);        // "Hi!"

用let或者const定义全局变量,是绑定而不是添加属性到全局对象。你只能映射而已~

// in a browser
let RegExp = "Hello!";
console.log(RegExp);                    // "Hello!"
console.log(window.RegExp === RegExp);  // false

const ncz = "Hi!";
console.log(ncz);                       // "Hi!"
console.log("ncz" in window);           // false

最佳实践:用let和const替代var吧

 

总结

let是健全的词法界定,比var更安全,更严格。如果是常量可以用const代替。

let不会变量声明提前,拥有块级作用域,循环等表现更优,const更具语义。

如果不考虑兼容性简直是上上之选啊。

 



评论
Login