JS中使用变量绑定数据,统一个变量不同的声明方式输出不同的值,那末我们一起来看看吧,Let's go!
1.块级绑定
var let const
首先解释一个概念:
变量提升Hosting:无论其实际声明位置在何处,都会被视为声明于所在函数的顶部,如果声明不在任意函数内,则视为在全局作用域的顶部。
初学需要花点儿时间来习惯变量提升,如果不理解这种思想可能会导致bug
因此引入块级作用域,让变量的生命周期更可控。
咱们来做道题测试测试吧
() => {
var a = 0;
if(true) {
a = 1;
function a() {};
a = 21;
console.log('in', a);
}
console.log('out', a);
}
正确答案是: in 21, out 1
详细讲解请看这里: https://mp.weixin.qq.com/s/UNYO-OsIul8_gUdcghIBwQ
块级作用域
让所声明的变量在指定块的作用域外无法被访问。块级作用域(又被称为词 法作用域)在如下情况被创建:
1. 在一个函数内部
2. 在一个代码块(由一对花括号包裹)内部
let
基本可以代替var,作用域在当前的代码块中
一对{}里面使用let声明变量,下面行的代码就可以使用此变量了
如果需要整个{}内都可以使用A变量,则需要把A变量放到{}顶部
function getValue(condition) {
if(condition) {
let value = 'blue';
console.log(value); // return value;
} else {
console.log(value);
return null;
}
console.log(value);
}
在这个例子中value 只在if{}里面才生效,其他地方没有value
TIPS:
1.禁止重复声明同一变量
() => {
var value = 1;
let value = 2; // 错误
}
function change(condition) {
var value = 1;
if(condition) {
let value = 2;
console.log(value); // return value;
} else {
return null;
}
console.log(value);
}
const 常量
const用来声明常量constant,常量初始化之后不能被改变,且必须在声明时就初始化。
const maxItems = 30;
const minItems; // 语法错误未初始化
let const 都是块级声明,语句块外部无法访问,变量也不会提升。
if (condition) {
const maxItems = 5;
// 其他代码
}
// maxItems 在此处无法访问
常量 maxItems 在 if 语句内被声明,在if{}外部无法被访问
var message = "Hello!"; let age = 25;
// 二者均会抛出错误
const message = "Goodbye!"; const age = 30;
变量已经被声明就不得用const再次声明。
const maxItems = 5;
maxItems = 6; // 抛出错误
const声明的常量不得再次赋值。
const 声明会阻止对于变量绑定与变量自身值的修改,这意味着 const 声明并不会阻止对 变量成员的修改。
const person = {name: "Nicholas"
};
// 工作正常
person.name = "Greg";
// 抛出错误
person = {
name: "Greg"
};
不能修改常量本身的值,但可以修改常量对象的属性值。
补充一个概念:‘暂时性死区’
if (condition) {
console.log(typeof value); // 引用错误
let value = "blue";
}
此处的 value 变量使用了 let 进行定义与初始化,但该语句永远不会被执行,
因为声明之 前的那行代码抛出了一个错误。
出现该问题是因为:value 位于暂时性死区
( temporal dead zone , TDZ )内。
该名称并未在 ECMAScript 规范中被明确命 名,但经常被用于描述 let 或 const 声明的变量为何在声明处之前无法被访问。
console.log(typeof value); // "undefined"
if (condition) {
let value = "blue";
}
当 typeof 运算符被使用时, value 并没有在暂时性死区内,因为这发生在定义 value 变 量的代码块外部。这意味着此时并没有绑定 value 变量,而 typeof 仅单纯返回了
"undefined" 。
for (var i = 0; i < 10; i++) {
process(items[i]);
}
// i 在此处仍然可被访问
console.log(i);
for (let i = 0; i < 10; i++){process(items[i]);
}
// i 在此处不可访问,抛出错误
console.log(i);
变量 i 仅在 for 循环内部可用,一旦循环结束,该变量在任意位置都不可访问。
IIFE
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push(function() { console.log(i); });
}
funcs.forEach(function(func) {func(); // 输出数值 "10" 十次
});
你原本可能预期这段代码会输出 0 到 9 的数值,但它却在同一行将数值 10 输出了十次。这是 因为变量 i 在循环的每次迭代中都被共享了,意味着循环内创建的那些函数都拥有对于同一 变量的引用。在循环结束后,变量 i 的值会是 10 ,因此当 console.log(i) 被调用时, 每次都打印出10 。
为了修正这个问题,开发者在循环内使用立即调用函数表达式(IIFEs),以便在每次迭代中 强制创建变量的一个新副本,示例如下:
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 到 9 依次输出
});
这种写法在循环内使用了 IIFE 。变量 i 被传递给 IIFE ,从而创建了value 变量作为自身 副本并将值存储于其中。 value 变量的值被迭代中的函数所使用,因此在循环从 0 到9 的过 程中调用每个函数都返回了预期的值。幸运的是,使用 let 与 const 的块级绑定可以在 ES6 中为你简化这个循环。
在循环内使用let声明
var funcs = [];
for (let i = 0; i < 10; i++) {funcs.push(function() {
console.log(i);
});
}
funcs.forEach(function(func) {func(); // 从 0 到 9 依次输出
}
在for-in中使用
var funcs = [],object = {
a: true,b: true,c: true
};
for (let key in object) {funcs.push(function() {
console.log(key);
});
}
funcs.forEach(function(func) {
func(); // 依次输出 "a"、"b"、 "c"
});
但是注意不要使用const来声明:
function getConst3() {
var arr = [];
for(const i = 0; i < 10; i++) {
arr.push(function() {
console.log(i);
});
}
arr.forEach(item => {
item();
});
}
但是可以在for-in和for-of中使用const:
for (const key in object) {funcs.push(function() {
console.log(key);
});
}
是因为,循环未每次迭 代创建了一个新的变量绑定,而不是试图去修改已绑定的变量的值
使用var定义变量时变量时全局变量,可以通过window.变量来访问(变成window的一个属性 这是js的工作方式),那这就意味着var可能会重写其他的变量。
使用let、const虽然会在全局创建新的绑定,但是不会覆盖全局对象的值,也不会有任何属性背添加到全局对象上。
可以用以下代码测试看看:
const RegExp = 'hi';
console.log(RegExp, window.RegExp, RegExp === window.RegExp);
var newWord = 'word';
console.log(‘ newWord ’ in window, window.newWord);
总结:
1.可以尽量使用let代替var(默认情况下使用let),常量使用const。
或者
默认情况下使用const,当变量需要被修改的时候才用let。‘其理论依据是大部分 变量在初始化之后都不应当被修改,因为预期外的改动是 bug 的源头之一’
2.let 与 const不会进行提升,并且 只会在声明它们的代码块内部存在。
不能在变量声明位置之前访问 它们,即便使用的是typeof 这样的安全运算符
3.块级绑定当前的最佳实践就是:在默认情况下使用 const ,而只在你知道变量值需要被更改 的情况下才使用 let 。
网友评论