ES6实训报告
let和const的用法?
var关键字的缺点
以往在JavaScript中,定义变量通常使用的var
关键词,由于JavaScript的变量提升机制,导致var
变量无论在何处声明,都会被提升到当前作用域的顶部。
例如:
function getNumber(isNumber) {
if (isNumber) {
var num = "7";
} else {
var notNum = "not number!";
console.log(num);
}
}
getNumber(false);
以上的代码在函数体中使用var
声明了变量num和notNum,由于变量提升机制,变量提升到当前作用域的顶部,控制台报错变量未定义。
变量提升后代码:
function getNumber(isNumber) {
var num;
var notNum;
if (isNumber) {
num = "7";
} else {
notNum = "not number!";
console.log(num);
}
}
getNumber(false);
由此可见,当传入参数为false
时,num变量未被复制,因此控制台输出undefined
与此同时,var
关键字声明的变量可以重复赋值,但在某些情况下会造成一些问题,例如:
function Sum(arrList) {
var sum = 0;
for (var i = 0; i < arrList.length; i++) {
var arr = arrList[i];
for (var i = 0; i < arr.length; i++) {
sum += arr[i];
}
}
return sum;
}
var arr = [1, 2, 3, 4, 5];
document.write(Sum(arr));
上述代码如果运行,将会卡死。因为在两层for
循环中,我们使用了同一变量i
进行赋值,代码在执行过程中,第二层的for
循环会覆盖外层变量i
的值,导致i
的值重复赋值为1,程序进入死循环状态。
使用 var
关键字定义的变量只有两种作用域,全局作用域和函数作用域,两者均不是块结构,会造成变量声明的提升。这可能出现下面这种问题:
function func() {
for (var i = 0; i < 5; i++) {}
document.write(i); // 5
}
func();
运行上述代码后,你会发现页面上会显示 5。我们虽然是在 for
循环中定义的 i
变量,但由于变量被提升到 for
语句之上,所以退出循环后,变量 i
并没有被销毁,我们能够在循环外获取它的值。
因此在ES6语法中新增let关键字和和const关键字,来弥补var关键字的不足之处。
let关键字的使用
解决变量提升机制问题
let
的作用域是块,解决了变量提升到作用域顶部的问题。
function getNumber(isNumber) {
if (isNumber) {
let num = "7";
} else {
let notNum = "not number!";
console.log(num);
}
}
getNumber(false);
执行如上代码:控制台报错num变量不存在。
原因:let
关键字声明的变量作用域是一个块,在上述代码中,num所在作用域是if{}
花括号块中,因此在else{}
块中无法访问到num变量。
解决变量重复声明问题
虽然 let
关键字声明的变量可以重新赋值,但是它与 var
关键字有所不同,let
关键字不能在同一作用域内重新声明,而 var
可以。
例如:
let i = 5;
let i = 6;
console.log(i);
控制台报错:i变量已经被定义。
然而在不同作用域内:
function Sum(arrList) {
var sum = 0;
for (let i = 0; i < arrList.length; i++) {
var arr = arrList[i];
for (let i = 0; i < arr.length; i++) {
sum += arr[i];
}
}
return sum;
}
var arr = [1, 2, 3, 4, 5];
document.write(Sum(arr));
此时代码正常运行,因为i
的作用域在不同作用域块中。因此在for
循环中比较适合使用let
关键字
解决非块级作用域的问题
var
关键字定义变量,只有两种作用域:
- 函数作用域
- 全局作用域
而这两种作用域都是非块级作用域。
let
关键字定义的变量是块级作用域,避免了变量提升。
function func() {
for (let i = 0; i < 5; i++) {}
console.log(i);
}
func();
在上段代码中控制台报错:i is not defined
因为let
声明的变量i
作用域仅在for循环的块中,当循环结束时i
即被销毁。因此在for循环之外不能访问到变量i
。
const关键字的使用
在ES6中,提供了关键字const
用于声明一个只读的变量,变量一旦声明,值就不会被改变,如果反复赋值则会报错。并且需要在定义时就对变量进行初始化。
对于 const
关键字定义的变量值,不可改变在于两个方面:
-
值类型:
值类型是指变量直接存储的数据:
const num = 20;
此处的
num
变量就是值类型,因为定义num变量的关键字是const
,因此变量num的值是不可变的 -
引用类型:
引用类型是指变量存储数据的引用,而数据是放在数据堆中,比如,用 const 声明一个数组:
const arr = ["一", "二", "三"];
此时,如果尝试修改数组,同样会报错。但是可以通过数组下标来对数组进行修改。
因为数组中保存的是数组的引用,并不是数组中的值。只要引用的地址不发生变化,程序就不会报错。
const arr = ["一", "二", "三"]; arr[0] = "四"; arr[1] = "五"; arr[2] = "六"; console.log(arr);
数组,对象和字符串解构赋值如何使用?
数组解构赋值
在es6之前,为变量赋值:
let a = 1;
let b = 2;
let c = 3;
在es6后允许写成这样:
let [a, b, c] = [1, 2, 3];
//打印
console.log(a)
console.log(b)
console.log(c)
对象解构赋值
解构不仅可以用于数组,还可以用于对象。
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
console.log(foo);
console.log(bar);
let { baz } = { foo: 'aaa', bar: 'bbb' };
console.log(baz );// undefined
字符串解构
const [a, b, c, d, e] = 'hello';
console.log(a); // "h"
console.log(b); // "e"
console.log(c);// "l"
console.log(d);// "l"
console.log(e); // "o"
可以发现此时将hello字符串的单字符赋值给了abcde
。
字符串模板如何使用?
模板字面量的基本用法
模板字面量:在JavaScript中,字面量代表由一些字符串组成表达式定义的常量。
在ES6之前,使用''
和""
包裹字符串。
在ES6中提高了反引号``
来包裹字符串,可以简化解决多行字符串和字符串占位符的问题。
多行字符串的处理
当处理多行文字时,在ES6之前,通常使用转义符\n
进行转换:
console.log('java/nscript')
但是遇到需要多次换行的字符串,需要手动加入转义符,操作麻烦。
因此在ES6语法中,使用反引号``
包裹字符串,定义在字符串中的空格、缩进和换行都会保留,不用认为加入转义符,简化了操作。
字符串占位符
在ES6之前,需要将变量和字符串放在一起输出时,通常采取+
来进行拼接,例如:
let a = 2;
let b = 4;
console.log("a = " + a + ", b = " + b + ", sum = " + (a + b));
由上述代码,可以看出该操作麻烦且容易出错。
因此在ES6中可以使用新增的反引号,在字符串中嵌入变量。字符串${变量名}字符串
。
let a = 2;
let b = 4;
console.log(`a=${a},b=${b},sum=${a+b}`);
将该代码与第一段代码比较,可以发现写法更为简单,易读性更强。
字符串模块调用函数
const sayHello = function () {
return 'hi 你好';
};
let str1 = `${sayHello()} OK Ok`;
console.log(str1);//hi 你好 OK Ok
展开运算符如何使用?
扩展运算符(...)
是ES6新语法,它可以将可迭代对象的参数在语法层面上进行展开。
语法格式:
// 在数组中的使用
let VariableName = [...value];
例如:
-
将字符串转为数组:
let str = 'abcd'; const arr = [...str] console.log(arr);//['a', 'b', 'c', 'd']
-
合并数组
let arr1 = [1,2,3] let arr2 = [4,5,6] let arr3 = [...arr1,...arr2] console.log(arr3) //[1, 2, 3, 4, 5, 6]
在对象上,我们主要有以下三种操作:
-
可以使用扩展运算符将一个对象的全部属性插入到另一个对象中,来创建一个新的对象。
let student = { name: "小白", age: 17, email: "1234@qq.com" }; let NewObj = { ...student }; console.log(NewObj);
-
可以使用扩展运算符给对象添加属性。
let student = { name: "小白", age: 17, email: "1234@qq.com" }; let NewObj = { ...student, id: 7 }; console.log(NewObj);
-
可以使用扩展运算符合并两个新对象。
let studentName = { name: "小白" }; let studentAge = { age: 17 }; let NewObj = { ...studentName, ...studentAge }; console.log(NewObj);
剩余参数如何使用?
rest参数又称为剩余参数,用于获取函数的多余参数。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
rest参数和扩展运算符在写法上一样,都是(...)
,但是两者的使用上截然不同
扩展运算符就像是 rest 参数的逆运算,主要用于以下几个方面:
- 改变函数的调用。
- 数组构造。
- 数组解构。
rest参数的语法格式:
// 剩余参数必须是函数的最后一个参数
myfunction(parameters, ...rest);
例如:
function add(a,...args){
console.log(a);//10
console.log(args);//数组[20,30]
}
add(10,20,30)
剩余参数和解构配合使用
let students = ['wangwu', 'zhangsan', 'lisi'];
let [s1, ...s2] = students;
console.log(s1); // 'wangwu'
console.log(s2); // ['zhangsan', 'lisi']
箭头函数如何使用?
箭头函数,就是用=>
来表示函数。箭头函数和普通函数都是用来定义函数的,但是在语法构成上不同,
普通函数语法:
let sum = function (a, b) {
return a + b;
};
console.log(sum(1, 2));
箭头函数语法:
let sum = (a,b)=>a+b;
console.log(sum(1,2));
箭头函数除了代码简洁以外,还解决了匿名函数的this指向问题。
在箭头函数中,this指向的时该函数所在的作用域所指向的对象,而不是使用所在作用域指向的对象。
而普通法函数的this指向调用该函数的对象。