var、let、const区别和优先级
- 优先级:const > let > var
- 三种声明方式中,第一优先使用的是const,如果希望变量被改变则用let,至于var最好不在代码出现
- var声明的变量没有块作用域
for (var i = 0; i < 5; i++) {
console.log("变量i循环内部->>",i)
}
console.log("变量i循环外部->>",i)
for (let j = 0; j < 5; j++) {
console.log("变量j循环内部->>",j)
}
console.log("变量j循环外部->>",j)
此处如果使用var,控制台依然会打印出i。原因是var没有块作用域
- let的出现有效的隔离了代码块内外的变量,使得代码的结构更清晰,维护起来更加容易。
- const在JS中用来声明常量,所谓常量就是只能赋值一次的变量。在JS中对const的使用是非常频繁的,当一个变量用来保存一个对象时(函数或其他对象),为了避免变量被修改通常会使用const来声明
const obj = {name:"张三"}
obj = {name:"李四"} // ❌ 对象不可改变
obj.name = "李四" // √ 属性可以改变
console.log(obj)
const fn = function () {
}
- const使用场景:
- 对于一些常量使用const
- 对于对象和函数也可以使用const
解构和展开
解构赋值
- 数组解构
const [d, e, f] = [40, 50, 60] // 可以在赋值时直接声明变量
console.log(d); // 40
console.log(e); // 50
console.log(f); // 60
[a=5, b=7] = [1]; // 赋值是可以指定默认值
console.log(a); // 1
console.log(b); // 7
let arr = ['孙悟空','猪八戒','沙和尚','唐僧']
const [a,b, ,d] = arr // 解构跳过元素
console.log(a); // 孙悟空
console.log(b); // 猪八戒
console.log(d); // 唐僧
const [a,b,...c] = arr // ...变量,会接收后面所有元素
console.log(a); // 孙悟空
console.log(b); // 猪八戒
console.log(c); // ['沙和尚','唐僧']
- 解构函数返回值
function f() {
return [1, 2];
}
let [a, b] = f();
console.log(a); // 1
console.log(b); // 2
- 对象解构
const obj = {
name:'孙悟空',
age:18,
gender:'男'
};
({name:a,age:b,gender:c} = obj); // 将name赋值给a,age赋值给b,gender赋值给c
console.log(a) // 孙悟空
console.log(b) // 18
console.log(c) // 男
const {name,gender,age} = obj; // 如果变量名和属性名一致,可以省略
// 对象的嵌套解构
const {inner:{size}} = {a: 10, b: 20, inner:{size: 5}}; // 将对象中inner.size赋值给变量size
console.log(size) // 5
- 利用数组的解构交换变量位置
let a, b;
a=10;
b=20;
// 常规交换
let tmp = a;
a = b;
b = tmp;
// 解构交换
[a, b] = [b ,a]
//解构 创建数组
let arr = [1, 3, 2];
[arr[1], arr[2]] = [arr[2], arr[1]]; // 交换数组中两个元素的位置
console.log(arr)
展开
- 函数展开:通过… 展开一个数组
function fn(a,b,c){
return a+b+c;
}
const arr = [1,2,3]
// 计算数组中三个数字的和
let result = fn(arr[0],arr[1],arr[2]);
let result = fn(...arr); // 通过... 展开一个数组
console.log(result)
- 数组展开
const arr = [1,2,3]
const arr2 = [...arr] // 相当于将arr浅复制给arr2
const arr2 = [0,...arr,4,5,6]
console.log(arr2)
- 对象展开
const obj = {
name:'孙悟空',
age:18,
gender:'男'
};
const obj2 = {...obj}; // 将obj在新的对象中展开,相当于浅拷贝
console.log(obj2);
const obj3 = {...obj, address: '花果山'}; // 添加元素
console.log(obj3);
箭头函数
使用
- 只有一个参数的箭头函数
- 参数 => 返回值
- 如果没有参数或多个参数,参数需要使用()括起来
- () => 返回值
- (a,b,c) => 返回值
- 箭头后面的值就是函数的返回值
- 返回值必须是一个表达式(有返回值的语句)
- 如果返回值是对象 必须加()
- 如果需要在箭头函数中定义复杂逻辑,可以直接在箭头后跟一个代码块
const fn = function (a){
return 'hello';
};
const fn2 = a => 'hello';
console.log(fn2(123));
const sum = (a, b) => a + b;
let result = sum(123, 345);
const sum = (a, b) => ({name:'孙悟空'});
const fn4 = (a, b) => {
if (a === 10){
a += 5;
}else {
a += 10;
}
return a+b;
};
区别
- 箭头函数没有arguments
function fn() {
console.log(arguments.length); // arguments保存当前函数的实参
}
fn('hello');
const fn2 = () => {
console.log(arguments)
}
fn2('hello') // arguments is not defined
- 剩余参数
function fn(a, b, ...args) {
console.log(args);
}
fn("1",2,3,5)
- 没有自己的this,他的this总是外层作用域的this
const fn3 = () => {
console.log(this) // Window{}
}
fn3()
const obj = {
hello:() => {
console.log(this) // 还是Window{}
}
}
obj.hello()
const obj2 = {
hello:function (){
const test = () => {
console.log(this) // obj2
}
test()
}
}
obj2.hello()
- 箭头函数中的this无法通过call()、apply()、bind()
- 箭头函数无法作为构造函数使用
模块化
初期的JavaScript项目是非常小的,并不需要引入模块化来对其进行处理。但是随着前端项目复杂度的提高,项目中的代码越来越多,引入模块化成为一个迫在眉睫的问题。
所谓的模块化指将一个大的项目拆分成一个一个小的模块。拆分模块的好处有很多,比如使代码变得结构清晰、易于维护、提高复用度等。传统的JS中引入外部的脚本也可以当成是一种初级的模块化方式,但那种方式存在着很多不足,对我们开发人员来说并不十分友好。所以有一些前辈开始设计新的模块化方法来对JS进行扩展,像CommonJS、AMD、ReauireJS等模块系统都是很好的尝试。CommonJS现在依然是Node.js中默认的模块化方式。
第三方的模块化进行的如火如荼,ECMA官方当然不能袖手旁观,于是就有了ES6的模块化方案。ES6的模块化分成两个部分:export和import。
Export(导出)
在创建JS模块时,我们通过export向模块外部暴露内容(函数、对象、原始值)。在其他模块中可以通过import引入这些内容。使用了export的模块会自动开启严格模式。
export导出的方式有两种:
- 默认导出
- 命名导出
// 导出变量(命名导出)
export let name1, name2, …, nameN;
export let name1 = …, name2 = …, …, nameN;
// 导出函数(命名导出)
export function functionName(){...}
// 导出类(命名导出)
export class ClassName {...}
// 导出一组
export { name1, name2, …, nameN };
// 重命名导出
export { variable1 as name1, variable2 as name2, …, nameN };
// 解构赋值后导出
export const { name1, name2: bar } = o;
// 默认导出
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };
// 聚合模块
export * from …; // 将其他模块中的全部内容导出(除了default)
export * as name1 from …; // ECMAScript® 2O20 将其他模块中的全部内容以指定别名导出
export { name1, name2, …, nameN } from …; // 将其他模块中的指定内容导出
export { import1 as name1, import2 as name2, …, nameN } from …; // 将其他模块中的指定内容重命名导出
export { default, … } from …;
Import(引入)
import用来引入其他模块中导出的内容,注意!只有通过export导出的内容才能够通过import引入。和export一样,使用了import的模块会自动启用严格模式。
// 引入默认导出
import defaultExport from "module-name";
// 将所有模块导入到指定命名空间中
import * as name from "module-name";
// 引入模块中的指定内容
import { export1 } from "module-name";
import { export1 , export2 } from "module-name";
// 以指定别名引入模块中的指定内容
import { export1 as alias1 } from "module-name";
import { export1 , export2 as alias2 , [...] } from "module-name";
// 引入默认和其他内容
import defaultExport, { export1 [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
// 引入模块
import "module-name";
类(Class)
类是对象的模板,类中定义了对象中包含了哪些属性和方法。也可以直接通过function来定义类,但这两种定义方式并不是完全通用。
class Person {
//属性
name = "孙悟空";
// 属性
age = 18;
// 方法
sayHello() {
console.log(`大家好,我是${this.name}`);
}
}
const p = new Person(); // 创建对象
p.sayHello(); // 调用方法
...