本文详细介绍ES6新增的let和const命令,阐述其块级作用域特性及与var的区别,并通过循环绑定示例说明变量提升问题。同时深入解析数组与对象的解构赋值语法,包括默认值设置、不完全解构及常见报错场景,帮助开发者掌握ES6核心变量声明与赋值技巧。
一、ECMAScript和JavaScript关系
JavaScript由Netscape公司创造,后提交至标准化组织ECMA进行标准化处理。由于JavaScript商标已归Netscape所有,ECMA制定的标准被命名为ECMAScript,后续版本均由其制定。
ES6作为JavaScript的下一个主要版本,引入了大量新特性,通常被视为JavaScript语言的重要更新。
二、let命令
ES6引入了let命令用于声明变量。其基本用法与var相似,但关键区别在于:使用let声明的变量仅在该命令所在的代码块内有效。
三、var与let定义变量的区别
<script>
//var的作用域是函数级的(函数内部定义变量只能函数里面使用)
// function showName()
// {
// var myName = "张学友";
// alert(myName + "欢迎您!"); //此处的myName为"张学友"
// }
// showName();
// alert(myName + "欢迎您!"); //此处会报错,myName只能在showName函数中使用
//var的作用域是函数级的(在代码块中定义的变量可以在代码块之外使用)
// if(1==1)
// {
// var myName = "张学友";
// }
// alert(myName + "欢迎您!"); //此处可以运行
//let的作用域是代码块级别的
// if(1==1)
// {
// let myName = "张学友";
// }
// alert(myName + "欢迎您!"); //此处会报错
//let不存在变量提升
// console.log(a); //报错
// let a = "apple";
// console.log(b); //undefined
// var b = "banana";
</script>
四、循环计数中var与let的区别
<script>
// for(var i = 1;i <= 10;i++)
// {
// //
// }
// alert(i); //此处会打印11,i在循环体内和循环体外都可以使用
//此时计数器的变量泄露成了全局变量
// for(let i = 1;i <= 10;i++)
// {
// //
// }
// alert(i); //此处会报错,i只在循环体内有效,在循环体外无效
// 输出十个11
// i是全局的,定时器代码在循环之后发生,所以打印十个11
// for (var i = 1; i <= 10; i++) {
// setTimeout(function(){
// console.log(i);
// })
// }
//输出1 2 3 4 5 6 7 8 9 10
for (let j = 1; j <= 10; j++) {
setTimeout(function(){
console.log(j);
})
}
</script>五、循环绑定网页元素事件中var与let的区别
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>循环绑定按钮事件</title>
</head>
<body>
<h2>点击三个按钮分别弹出1,2,3</h2>
<input type="button" class="myButton" value="第一个按钮" />
<input type="button" class="myButton" value="第二个按钮"/>
<input type="button" class="myButton" value="第三个按钮"/>
</body>
</html>
<script>
//在此案例中i是全局的,点击按钮发生在循环之后,所以打印结果全部为4
// var list = document.getElementsByClassName("myButton");
// for(var i = 0;i < list.length;i++)
// {
// list[i].onclick = function(){
// alert(i+1);
// }
// }
//上述代码不能打印1,2,3,而是打印4,需要采取JS闭包来解决此问题;
//闭包就是能够读取其他函数内部变量的函数
// var list = document.getElementsByClassName("myButton");
// for(var i = 0;i < list.length;i++)
// {
// list[i].onclick = (function(num)
// {
// return function(){
// alert(num);
// }
// })(i+1);
// }
//如果使用ES6中let关键字则不存在上面演示的问题
var list = document.getElementsByClassName("myButton");
for(let i = 0;i < list.length;i++)
{
list[i].onclick = function(){
alert(i+1);
}
}
</script>三、const命令
使用const声明只读常量。一旦声明,该常量的值便不可更改。
<script>
// const PI = 3.14;
// PI = 3.15; //此处会报错,const声明的变量不能改变其值
//const一旦声明变量,就必须立即初始化,不能留到以后赋值。
//const PI; //报错
//const实际上保证的,并不是变量的值不得改动,
//而是变量指向的那个内存地址所保存的数据不得改动。
const arr = [];
arr.push('jack'); //可以执行
arr.push("rose"); //可执行
console.log(arr[0]);
console.log(arr[1]);
</script>四、变量的解构赋值
1、数组的解构赋值
ES6允许按照特定模式,从数组和对象中提取值并对变量进行赋值。
// let a = 1;
// let b = 2;
// let c = 3;
//上述代码可以如下编写(从数组中提取值,按照对应位置,对变量赋值)
// let[a,b,c]=[1,2,3];六、数组解构赋值案例
//let [a, [[b], c]] = [1, [[2], 3]]; //a=1,b=2,c=3
//let [ , , c] = ["jack", "rose", "mike"]; //c=mike
//let [x, , y] = [1, 2, 3]; //x=1,y=3
//let [head, ...tail] = [1, 2, 3, 4]; //head=1,tail=[2,3,4]
//let [x, y, ...z] = ['a']; //x=a,y=undefined,z=[]七、解构不成功的情况,变量值将等于undefined
//let [foo] = []; //解构不成功,foo=undefined
//let [bar, foo] = [1]; //bar=1,foo解构不成功foo=undefined八、不完全解构
当左侧模式仅匹配右侧部分时,解构仍可成功
let [x, y] = [1, 2, 3]; //x=1,y=2九、字符串解构(将字符串视为数组处理)
let [a, b, c, d, e] = 'hello';
console.log(a);
console.log(b);
console.log(c);
console.log(d);
console.log(e);十、默认值设置
解构赋值支持指定默认值。
//let [foo = true] = []; //foo=true;
//let [x, y = 'b'] = ['a']; // x='a', y='b'
//let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
//let [x = 1] = [null]; //x=null(只有当一个数组等于undefined,默认值才会生效)默认值可以引用其他已声明的解构变量,但该变量必须在此之前声明。
//let [x = 1, y = x] = []; // x=1; y=1
//let [x = 1, y = x] = [2]; // x=2; y=2
//let [x = 1, y = x] = [1, 2]; // x=1; y=2
//let [x = y, y = 1] = []; // ReferenceError: y is not defined2、对象的解构赋值
解构操作同样适用于对象。
let { foo, bar } = { foo: 'aaa', bar: 'bbb' }; //foo='aaa', bar='bbb'上述代码看似与数组解构无异,但存在关键差异:
(1)数组解构中,元素按顺序排列,变量取值取决于位置;
(2)对象解构中,属性无顺序概念,变量必须与属性名一致才能正确取值;
十一、对象解构示例
let { bar, foo } = { foo: 'aaa', bar: 'bbb' }; //foo="aaa" bar= "bbb"
let { baz } = { foo: 'aaa', bar: 'bbb' }; //baz = undefined,解构失败,值为undefined十二、利用对象解构便捷地获取现有对象方法并赋值给变量
// 例一
let { log, sin, cos } = Math; //将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上
// 例二
const { log } = console; //将console.log赋值到log变量,简化代码
log('hello') // hello若变量名与属性名不一致,需采用特定写法:
let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; //baz = "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj; //f = 'hello' l = 'world'这表明对象解构赋值实际上是以下形式的简写:
let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };实际被赋值的是后者,而非前者。
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
//baz = "aaa" foo = error: foo is not defined与数组类似,解构也可用于嵌套结构的对象。
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"注意,此时p属于模式而非变量,因此不会被赋值。若需将p也作为变量赋值,可采用如下写法。
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]十三、默认值规则
let {x = 3} = {};
x // 3
let {x, y = 5} = {x: 1};
x // 1
y // 5
let {x: y = 3} = {};
y // 3
let {x: y = 3} = {x: 5};
y // 5
let { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"默认值生效的前提是对象属性值严格等于undefined。
var {x = 3} = {x: undefined};
x // 3
var {x = 3} = {x: null};
x // null十四、注意事项
若要将已声明的变量用于解构赋值,需格外谨慎。
// 错误的写法
let x;
{x} = {x: 1};上述写法会报错,因为JavaScript引擎会将{x}解析为代码块。解决方法是不将大括号置于行首。
此问题可通过调整语法结构解决。
// 正确的写法
let x;
({x} = {x: 1});由于数组本质上是特殊的对象,因此可对数组进行对象属性的解构。
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr; //利用数组下标解构赋值
first // 1
last // 3至此,关于ES6基础知识的介绍结束,希望对学习有所帮助,欢迎支持本站。