JavaScript:神奇的ES6之旅
一、let 和 const
const和let是在ES6中引入的两个新的变量声明关键字,用于声明变量的作用域。
1.const
const用于声明一个常量,其值在声明后不能被修改。常量必须在声明时进行初始化,而且不能再次赋值
const num = 1;
num = 3;
const适合用于保存不可变的值,如数学常数、配置项等
2.let
let用于声明块级作用域的变量,它与var相比具有更小的作用域范围。在块级作用域内部声明的变量只在该块级作用域内有效,而且不会被提升到函数作用域
function fun() {let x = 10;if (true) {let x = 20;console.log(x);}console.log(x);
在使用块级作用域时,可以避免变量之间的命名冲突和问题。而var存在一些作用域上的问题,它声明的变量属于函数作用域或全局作用域,而不是块级作用域,因此在循环或条件语句中声明的变量会被提升到外部函数作用域
所以我们更倾向于使用let,var不再经常使用了
二、模板字符串
1.模板字符串是什么
模板字符串是在JavaScript中使用的一种特殊字符串语法。它使用反引号(`)包围,并允许在字符串中插入变量、表达式和换行符等
2.1.1插入变量
可以在字符串中插入变量,变量会被解析并替换为实际的值
const name = "cc";
const arr = `你好 ${name}!`;
console.log(arr);
2.1.2执行表达式
这样可以在字符串中进行复杂的运算或逻辑操作
const a = 10;
const b = 5;
const result = `${a} + ${b} = ${a + b}`;
console.log(result);
2.1.3多行字符串
在模板字符串中可以直接使用换行符,以方便创建多行文本
const arr = `我
喜欢
猫猫`;
console.log(arr);
2.模板字符串的注意事项
- 反引号`包围:模板字符串必须使用反引号`,而不是单引号或双引号来包围
- 字符串中的插入项:使用${}来包裹要插入的变量或表达式
- 转义字符:如果字符串中需要使用反引号`,则需要使用转义字符\进行转义
- 换行字符:模板字符串中的换行字符会被保留。如果希望字符串换行,可使用显式的换行符\n
- 嵌套模板字符串:模板字符串可以嵌套在彼此之内,以创建更复杂的字符串结构。
三、箭头函数
1.箭头函数是什么
箭头函数是在ES6中引入的一种新的函数声明语法
3.1.1箭头函数的语法
(argument1, argument2, ...) => {// 函数体
}
其中,如果只有一个参数,那么括起参数的括号可以省略,如果函数体只有一行,那么对应的分号和花括号也可以省略
3.1.2箭头函数的特点
- 相对于常规函数,箭头函数提供了更简洁的语法形式,减少了冗余的代码。
- 箭头函数没有自己的this上下文,继承了父级作用域的this值
- 箭头函数也没有自己的arguments对象,但可以通过使用rest参数(...args)来获取传递给函数的所有参数。
- 由于没有自己的this值,箭头函数不能用作构造函数来创建对象实例,即无法使用new关键字调用箭头函数。
const add = (a, b) => { return a + b;
};
const greet = name => `你好, ${name}!`;
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(num => num * 2);
2.this指向
3.2.1 全局作用域中的 this 指向
在严格模式下,全局作用域中的 this 的值是 undefined。在非严格模式下,它会指向全局对象window
严格模式:
"use strict";
console.log(this);
非严格模式:
console.log(this);
3.2.2一般函数中的this指向
在对象的方法中,即使在严格模式下,方法中的 this 仍然会指向调用该方法的对象
"use strict";
const obj = {name: "cc",hh: function() {console.log(this); }
};
obj.hh();
如果通过构造函数创建对象时,this 在严格模式下指向新创建的对象。但在非严格模式下,如果构造函数内部没有显式设置 this 的值,则 this 可能会指向全局对象
3.2.3.箭头函数中this指向
箭头函数没有自己的 this 绑定,它会捕获其外部的词法作用域中的 this 值,并沿用该值。因此,在箭头函数内部,this 的指向是固定的,指向定义箭头函数时所在的作用域中的 this。
const obj = {name: "cc",hh: () => {console.log(this.name); }
};
3.2.4回调函数中的 this 绑定
const button = document.querySelector("button");
button.addEventListener("click", () => {console.log(this);
});
3.不适用箭头函数的场景
3.3.1构造函数
由于箭头函数没有自己的 this 绑定,它无法通过 new 关键字创建实例对象。箭头函数的 this 始终指向其外部词法作用域中的 this 值,而不会根据调用方式或绑定调用者来改变。
const People = () => {this.name = "cc";
};
const people = new People();
3.3.2需要 this 指向调用对象的情况
对象方法:当需要在对象中定义方法,并且需要通过 this 来引用对象自身时,箭头函数不适用。箭头函数的 this 始终继承自外部词法作用域,无法根据调用方式来动态绑定
const obj = {name: "cc",hh: () => {console.log(`你好, ${this.name}!`); }
};
动态绑定 this:如果需要根据调用方式动态绑定 this 的值,例如通过 call()、apply() 或 bind() 显式改变其 this 值,那么箭头函数就不适合使用。箭头函数的 this 始终保持不变
3.3.3需要使用函数的 arguments 对象
箭头函数没有自己的 arguments 对象,无法访问传递给函数的参数集合。
4.箭头函数的应用
3.4.1简化函数表达式
箭头函数提供了一种更简洁的函数表达式语法,特别适用于传递匿名函数或回调函数。
// 传统函数表达式
const sum = function(a, b) {return a + b;
};// 箭头函数
const sum = (a, b) => a + b;
3.4.2数组遍历与转换
结合数组的map()、filter()和reduce()等方法,可以使用箭头函数对数组进行快速遍历、筛选和转换操作。
const number = [1,9, 83, 32, 14, 75];
const doubled = number.map(num => num * 2);
const evenNumber = number.filter(num => num % 2 === 0);
const sum = number.reduce((total, num) => total + num, 0);
3.4.3箭头函数作为回调函数
由于箭头函数没有自己的this值,因此常用于解决回调函数中this指向的问题。
const obj = {name: "cc",hh: function() {setTimeout(() => {console.log(`你好, ${this.name}!`);}, 1000);}
};
obj.hh();
3.4.4更简洁的函数嵌套
当需要在一个函数内部定义另一个函数时,可以使用箭头函数来简化语法。
function sum() {return (a, b) => a + b;
}
const add = sum();
console.log(add(2, 3));
3.4.5对象方法的简洁定义
当定义对象方法时,可以使用箭头函数来简化语法。
const obj = {name: "cc",hh: () => {console.log(`你好, ${this.name}!`);}
};
obj.hh();
四、解构赋值
1. 数组的解构赋值
原理:
- 数组解构赋值通过模式匹配,按照索引位置进行赋值
- 当进行解构赋值时,可以直接将一个数组[]赋给等号左侧的模式
- 可以使用默认值来指定缺失的元素取值
// 基本用法
const [a, b, c] = [1, 4, 7];
console.log(a); // 输出: 1
console.log(b); // 输出: 4
console.log(c); // 输出: 7// 使用默认值
const [x, y, z = 1] = [3, 8];
console.log(x); // 输出: 3
console.log(y); // 输出: 8
console.log(z); // 输出: 1(默认值)
2. 对象的解构赋值
原理:
- 对象解构赋值通过模式匹配,按照属性名称进行赋值
- 当进行解构赋值时,可以直接将一个对象{}赋给等号左侧的模式
- 可以使用默认值来指定缺失的属性取值
// 基本用法
const {name, age} = {name: "cc", age: 19};
console.log(name);
console.log(age);// 使用别名
const {name: personName, age: personAge} = {name: "lele", age: 19};
console.log(personName);
console.log(personAge); // 使用默认值
const {firstName = "Unknown", lastName = "Unknown"} = {firstName: "chuan"};
console.log(firstName);
console.log(lastName);
注意:将一个已经声明的变量用于解构赋值,整个赋值需在圆括号中进行
4.2.1对象的解构赋值可以取到继承的属性或方法
当进行对象解构赋值时,如果目标对象的属性并不存在,解构赋值表达式会继续向上查找该属性;如果目标对象的属性在原型链中存在,则可以成功提取到该属性的值
function People(name) {this.name = name;
}People.prototype.hh = function() {console.log(`你好, ${this.name}!`);
};function Student(name, grade) {People.call(this, name);this.grade = grade;
}Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.study = function() {console.log(`${this.name}的成绩是${this.grade}.`);
};const student = new Student('cc', 19);// 对象解构赋值取到继承的属性
const { name, grade } = student;
console.log(name);
console.log(grade); // 解构赋值取到继承的方法
const { cc, study } = student;
cc();
study();
3. 其他数据类型的解构赋值
4.3.1字符串的解构赋值
可以将字符串按照字符进行解构赋值
const [a, b, c] = 'cgh';
console.log(a);
console.log(b);
console.log(c);
4.3.2数值和布尔值的解构赋值
先将数值和布尔值转换为对应的包装对象类型(Number、Boolean),然后再进行解构赋值
const {toString: numToString} = 250;
console.log(numToString === Number.prototype.toString);
const {valueOf: boolValueOf} = true;
console.log(boolValueOf === Boolean.prototype.valueOf);
4.3.3undefined 和 null 的解构赋值
在解构赋值时,如果源值是 undefined 或者 null,则会使用默认值
const [x = 1, y] = [undefined, 2];
console.log(x);
console.log(y);
const {z = 'default'} = {z: null};
console.log(z);
注意: 在解构赋值中,如果目标没有对应的值,则可以使用默认值来指定默认取值。而 undefined 和 null 是不能进行解构赋值的
五、对象字面量的增强
1.属性和方法的简洁表示法
- 对象字面量: 一种创建和初始化对象的方式,使用花括号 {} 来定义一个对象,并通过键值对来指定对象的属性和方法
- 属性的简洁表示法:当属性的键名与变量名相同时,可以使用简洁表示法来定义属性。简洁表示法直接将变量名作为属性名,并自动将变量的值作为属性值
const name = 'cc';
const age = 19;
const people = {name, age
};
console.log(people.name);
console.log(people.age);
2.方法的简洁表示法
在对象字面量中,可以使用函数字面量来定义一个对象的方法。使用简洁表示法时,可以省略冒号和 function 关键字,直接将函数体作为方法的值
const person = {name: 'cc',hh() {console.log(`你好, 我的名字是 ${this.name}`);}
};
person.sayHello();
3.方括号表示法
方括号表示法是访问对象属性的一种语法,使用方括号 [] 来引用属性名或计算属性。这种表示法可以动态地获取和设置对象的属性
5.3.1属性访问
通过方括号表示法,可以使用变量或表达式作为属性名,从而动态地获取对象的属性值。示例代码如下:
const obj = {name: 'cc',age: 19
};
const propertyName = 'name';
console.log(obj[propertyName]);
5.3.2动态属性名
方括号表示法还可以用于动态地设置对象的属性名,即使属性名是通过变量或表达式计算得到的
const obj = {};
const propertyName = 'name';
obj[propertyName] = 'cc';
console.log(obj.name);
注意: 在使用方括号表示法访问属性时,属性名可以是任何字符串或能够被转换为字符串的表达式。方括号内的属性名会被解析为字符串,以便与对象的属性进行匹配
六、函数参数的默认值
- 概念: 在定义函数时,为参数提供一个默认的初始值。这样,在调用函数时如果没有传递相应参数的值,就可以使用默认值作为参数的值。
- 用法: 函数参数的默认值可以在函数定义的括号内直接设置,使用 = 运算符来指定默认值。
function hh(name = 'cc') {console.log('你好' + name);
}
hh();
hh('lele');
注意: 参数的默认值的应用是惰性求值的,即默认值在函数每次调用时都会被重新计算
1.默认值的生效条件
默认值只会在参数值为 undefined 时生效。如果传递了参数但不为 undefined(例如 null、空字符串等),则默认值不会生效。当没有传递对应的参数(即没有提供参数值)时,默认值会生效。
function hh(name = 'cc') {console.log('你好' + name);
}
hh();
hh(undefined);
hh(null);
hh('lele');
2.默认值表达式
默认值可以是任何合法的表达式,包括调用函数、三元运算符、数学运算等。
默认值表达式在定义函数时就会被计算,而不是在每次函数调用时计算。
3.设置默认值的小技巧
- 函数参数的默认值,最好从参数列表的右边开始设置
- 默认值可以使用函数参数的默认值或其他局部变量
- 可以通过使用逻辑运算符(如 ||)来提供默认值,如果左侧操作数为 undefined,那么返回右侧操作数
// 使用其他局部变量作为默认值
function combineStrings(str1, str2 = '') {const combinedString = str1 + ' ' + str2;console.log(combinedString);
}combineStrings('Hello');
combineStrings('Hi', 'hello');// 使用逻辑运算符设置默认值
function hh(name) {name = name || 'Anonymous';console.log('你好' + name);
}
hh();
hh('cc');
七、剩余参数
剩余参数是 ES6 中引入的一种语法,用于声明一个函数接收可变数量的参数,并将这些参数表示为一个数组。剩余参数使用三个点(…)在函数参数列表中表示。
1.剩余参数语法
在函数定义时,使用三个点(…)后跟一个参数名称来声明剩余参数。
function fun(...args) {// 函数体
}
例子:剩余参数以数组的形式表示传递给函数的所有多余参数
function sum(...numbers) {let total = 0;for (let i = 0; i < numbers.length; i++) {total += numbers[i];}return total;
}
console.log(sum(1, 2, 3, 4, 5));
2.结合其他参数使用
剩余参数可以与其他参数一起使用,但必须是最后一个参数
function hh(greet, ...names) { console.log(greet + " " + names.join(", "));
}
greet("hi", "cc", "lele", "chuan");
八、展开运算符
展开运算符是 ES6 中引入的一种语法,用于在某些上下文中将数组或对象展开为单独的元素。展开运算符使用三个点(…)作为前缀
1.展开数组:
在函数调用、数组字面量、数组解构赋值等场景中,可以使用展开运算符将数组展开为独立的元素
const numbers = [1, 2, 3];
console.log(...numbers);
const sum = (a, b, c) => a + b + c;
console.log(sum(...numbers));
2.合并数组
使用展开运算符还可以合并多个数组为一个新数组
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const add = [...arr1, ...arr2];
console.log(add);
3.复制数组或对象
展开运算符可以用于浅复制数组或对象
const arr = [1, 2, 3];
const newArr = [...arr];
console.log(newArray);
const o = { a: 1, b: 2 };
const newObject = { ...o};
console.log(newO);
4.合并对象属性
在对象字面量中,展开运算符可以用于合并多个对象的属性
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const add = { ...obj1, ...obj2 };
console.log(add);
九、set和map数据结构
1.Set 数据结构
Set 是一种有序且唯一的集合,它的值可以是任何类型。Set 中的值是不重复的,重复的值将被自动去重
常见的 Set 操作方法:
- add(value): 向 Set 中添加一个值
- delete(value): 删除 Set 中指定的值
- has(value): 检查 Set 中是否包含指定的值
- size: 返回 Set 中的元素个数
- clear(): 清空 Set 中的所有元素
const set = new Set();
set.add(1);
set.add(2);
set.add(3);
set.add(2);
console.log(set);
console.log(set.has(2));
console.log(set.size);
set.delete(2);
console.log(set);
set.clear();
console.log(set);
2.Map 数据结构
Map 是一种用于存储键值对的有序列表,其中的键唯一且值可以是任意类型
常见的 Map 操作方法:
- set(key, value): 向 Map 中添加一个键值对
- get(key): 获取指定键的值
- delete(key): 删除指定键的键值对
- has(key): 检查 Map 中是否包含指定的键
- size: 返回 Map 中键值对的数量
- clear(): 清空 Map 中所有的键值对
const map = new Map()
map.set('name', 'cc');
map.set('age', 19);
map.set('gender', 'female');
map.set('name', 'Blele');
console.log(map);
console.log(map.get('age'));
console.log(map.size);
map.delete('gender');
console.log(map);
map.clear();
console.log(map);
十、遍历器与for…of循环
1.遍历器
遍历器是一种接口,提供了一种统一的方式来遍历数据结构中的元素。它可以用于遍历Array、String、Set、Map 、NodeList、arguments等可迭代对象 —— 具有内置符号 方法的对象
遍历器具有一个 next() 方法,每次调用该方法都会返回一个包含 value 和 done 两个属性的对象。
- value 表示当前遍历到的值。
- done 表示遍历是否结束。结果为布尔值,done: true时结束
const hd = [1, 2, 3];
const arr = hd[Symbol.iterator]();
console.log(arr.next());
console.log(arr.next());
console.log(arr.next());
console.log(arr.next());
2.for...of 循环
for...of 循环是一种语法结构,用于遍历支持遍历器的可迭代对象,如数组、字符串、Set、Map NodeList、arguments
const hd = [1, 2, 3];
for (let item of hd) {console.log(item);
}
在 for...of 循环中,每次迭代都会自动调用可迭代对象的遍历器的 next() 方法,并将返回的 value 赋值给循环变量。循环会在遍历器返回 { done: true } 表示遍历结束时停止。