ES6新特性详解
文章目录
- 1. let和const
- 1.1 let声明变量
- 1.2 const声明常量
- 2. 模板字符串
- 3. 解构赋值
- 3.1 数组的解构赋值
- 3.2 对象的解构赋值
- 4. 函数扩展
- 4.1 参数默认值
- 4.2 剩余参数
- 4.3 箭头函数
- 5. 对象扩展
- 5.1 对象简写
- 5.2 属性名表达式
- 5.3 扩展运算符
- 6. Symbol
- 7. Iterator和Generator
- 7.1 Iterator
- 7.2 Generator
- 8. Proxy和Reflect
- 8.1 Proxy
- 8.2 Reflect
- 9. Promise
- 10. Async和Await
- 10.1 Async
- 10.2 Await
- 11. 类
- 11.1 类的定义和使用
- 11.2 类的继承
- 12. 模块
- 12.1 export
- 12.2 import
1. let和const
1.1 let声明变量
var 和 let 关键字的区别:
| 关键字 | 是否能重复声明变量 | 是否有块作用域 | 是否有变量提升 | 是否影响顶层对象 |
|---|---|---|---|---|
var | √ | × | √ | √ |
let | × | √ | × | × |
1.let 不允许重复声明变量
// var允许重复声明变量
var a = 10;
var a = 10;
// let不允许重复声明变量
let a = 10;
let a = 10; // Uncaught SyntaxError: Identifier 'a' has already been declared
2.let 声明的变量有块作用域
// var声明的变量,没有块作用域
if (true) {var a = 10;console.log(a); // 10
}console.log(a); // 10
// let声明的变量,有块作用域
if (true) {let a = 10; console.log(a); // 10
}console.log(a); // Uncaught ReferenceError: a is not defined
3.let 声明的变量,没有变量提升
/* 由于有变量提升,以下代码会转换成如下:
var a;
console.log(a);
a = 10; */// var声明的变量,有变量提升
console.log(a); // undefined
var a = 10;
// let声明的变量,没有变量提升
console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization
let a = 10;
4.let 声明的变量,不会与顶层对象挂钩
顶层对象:在broswer环境中,指window对象;在node环境中指global对象
// var声明的变量,会与顶层对象挂钩
var a = 10;
console.log(window.a); // 10
// let声明的变量,不会与顶层对象挂钩
let a = 10;
console.log(window.a); // undefined
1.2 const声明常量
const 拥有 let 的全部特性,与 let 不同的是,const声明的变量是常量,一经声明,无法修改。
1.const声明的变量无法修改
// let声明的变量,可以修改
let a = 10;
a = 20;
// const声明的变量,无法修改
const a = 10;
a = 20; // Uncaught TypeError: Assignment to constant variable
2.const声明的变量必须声明时就初始化
const a; // Uncaught SyntaxError: Missing initializer in const declaration
3.当变量是对象时,虽然不能修改对象名,但是可以修改对象的内部属性
解释:因为对象是引用类型,对象名存的是一个地址,而改变对象的内部属性,并没有改变地址本身。
const obj = {name: "Bill",age: 18
};obj.age = 28;
console.log(obj); // {name: 'Bill', age: 28}
let和const的使用场景:默认情况下使用const,在知道变量值需要修改时使用let
2. 模板字符串
模板字符串:其实就是占位符,这样就可以简化字符串拼接。
1.用于字符串拼接
const name = "Bill";
const age = 18;
const person = `my name is ${name}, my age is ${age}`;
console.log(person); // my name is Bill, my age is 18
2.支持使用表达式
// 1.支持四则运算
const a = 10;
const b = 20;
const result = `result is ${a + b}`;
console.log(result); // result is 30// 2.支持三元表达式
const isEqual = `结果是${a === 10 ? "相等" : "不相等"}`;
console.log(isEqual); // 结果是相等
3. 解构赋值
解构赋值:用于赋值运算,可以简化赋值。
3.1 数组的解构赋值
1.简化数组的赋值
const arr = [1, 2, 3];const [a, b, c] = arr; // 等价于 a=1, b=2, c=3
console.log(a, b, c); // 1 2 3const [d, , e] = arr; // 等价于 d=1, e=3
console.log(d, e); // 1 3
2.嵌套情况下的数组赋值
const arr = [1, [2, 3, 4], 5];
const [a, [b, c], d] = arr; // 等价于 a=1, b=2, c=3, d=5
console.log(a, b, c, d); // 1 2 3 5
3.2 对象的解构赋值
1.简化对象的赋值
const obj = {name: "Bill",age: 18
};const { name, age } = obj; // 等价于 name=obj.name, age=obj.age
console.log(name, age); // Bill 18
2.声明的变量名需要与对象的属性名一致时,否则在对象的属性名中匹配不到,得到的值是undefined
对象的解构赋值,变量赋值时会与属性名匹配,不会按照声明变量的前后顺序匹配
const obj = {name: "Bill",age: 18,addr: "Shanghai"
};const { name, addr, a } = obj; // 等价于 name=obj.name, addr=obj.addr
console.log(name, addr, a); // Bill Shanghai undefined
3.嵌套情况下的对象赋值
const obj = {name: "Bill",age: 18,other: {addr: "Shanghai",email: "xxx@163.com"}
};const {name,age,other: { email }
} = obj; // 等价于 name=obj.name, age=obj.age, email = obj.other.email
console.log(name, age, email); // Bill 18 xxx@163.com
4. 函数扩展
4.1 参数默认值
参数默认值:不传参时,函数使用默认的参数值,传参后会覆盖默认值。
function fn(a, b = 10) {console.log(a, b);
}fn(10); // 10 10
fn(10, 20); // 10 20
4.2 剩余参数
剩余参数:也称可变参数,剩余参数语法允许将一个不定数量的参数表示为一个数组。
function fn(a, b, ...args) {console.log(args);
}fn(10, 20, 30, 40, 50); // [30, 40, 50]
4.3 箭头函数
箭头函数:箭头函数可用于简化匿名函数的定义,使书写更为简洁。
1.无参数、无返回值的箭头函数
// 匿名函数写法,无参数、无返回值
const fn = function () {console.log(100);
};fn();
// 箭头函数写法,无参数、无返回值
const fn = () => {console.log(100);
};fn();
2.有返回值的箭头函数
// 匿名函数写法,有返回值
const fn = function () {console.log(100);return 100;
};
// 箭头函数写法,有返回值// 1.函数内部只有 return,无其它内容
const fn1 = () => 100;
const fn2 = () => ({ name: "Bill", age: 18 }); // 返回的是对象时,要使用小括号包裹起来// 2.函数内部除了有 return,还有其它内容
const fn3 = () => {console.log(100);return 100;
};
3.带参数的箭头函数
// 匿名函数写法,带参数
const fn = function (a, b) {console.log(a + b);return a + b;
};
// 箭头函数写法,带参数// 1.只有一个参数时,可以省略括号
const fn1 = a => {console.log(a);
};const fn2 = a => a;// 2.带多个参数时,不可省略括号
const fn3 = (a, b) => a + b;const fn4 = (a, b) => {console.log(a + b);return a + b;
};
4.箭头函数没有this
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><button value="按钮">点击按钮</button><script>const btn = document.querySelector("button");btn.addEventListener("click", function () {console.log(this.value); // 按钮// 使用匿名函数const fn = function () {console.log(this.value); // undefined};fn();});</script></body>
</html>
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><button value="按钮">点击按钮</button><script>const btn = document.querySelector("button");btn.addEventListener("click", function () {console.log(this.value); // 按钮// 使用箭头函数const fn = () => {console.log(this.value); // 按钮};fn();});</script></body>
</html>
注:监听事件的函数,要写成匿名函数,不要写成箭头函数,否则this指向的就是window
5. 对象扩展
5.1 对象简写
对象简写:简写对象的属性和方法
- 当属性名和属性值相同时,可以简写为只写一个属性名
- 可以省略方法中的
:function
// es5写法
const name = "Bill";
const obj = {name: name,test: function () {}
};
// es6写法
const name = "Bill";
const obj = {name,test() {}
};
5.2 属性名表达式
属性名表达式:对象的属性名,可以使用变量和表达式的方式命名
const name = "a";
const obj = {[name]: "Bill",[name + "bc"]: "Jackson"
};console.log(obj); // {a: 'Bill', abc: 'Jackson'}
注:对象简写和属性名表达式不能同时使用
5.3 扩展运算符
扩展运算符:用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中
- 对象的扩展运算符:用于拷贝对象属性
- 数组的扩展运算符:将数组分割为参数序列、拷贝数组
1.拷贝对象
const obj1 = { name: "Bill", age: 18 };
const obj2 = { name: "Jackson" };
const obj3 = { addr: "Shanghai" };
const obj = { ...obj1, ...obj2, ...obj3 };
console.log(obj); // {name: 'Jackson', age: 18, addr: 'Shanghai'}
注:当对象有同名属性时,后合并的对象,会覆盖之前的对象的属性
2.拷贝数组
const arr1 = [10, 20, 30];
const arr2 = [10, 40, ...arr1];
console.log(arr2); // [10, 40, 10, 20, 30]
3.将数组分割为参数序列
const arr = [10, 30, 50];
console.log(Math.max(10, 20, ...arr)); // 50
剩余参数的
...和扩展运算符...的区别:
- 剩余运算符:把多个参数合并为一个数组
- 扩展运算符:把一个数组分割为多个参数
6. Symbol
Symbol:是一种基本数据类型,表示独一无二的值。
1.创建Symbol变量
// 1.创建不带描述的Symbol变量
const s1 = Symbol();
console.log(s1); // Symbol()// 2.带描述的Symbol变量
const s2 = Symbol("Symbol2"); // 传入的字符串为Symbol变量的描述
console.log(s2); // Symbol(Symbol2)
注:Symbol是基本数据类型,不是对象类型,所以不能使用new创建Symbol变量
2.Symbol的值是唯一的
const s1 = Symbol();
const s2 = Symbol();
console.log(s1 === s2); // falseconst s3 = Symbol("Symbol");
const s4 = Symbol("Symbol");
console.log(s3 === s4); // false
3.Symbol变量不能进行运算
const s = Symbol();
console.log(s + "hello"); // Uncaught TypeError: Cannot convert a Symbol value to a string
7. Iterator和Generator
7.1 Iterator
迭代:从一个数据集合中按照一定的顺序,不断取出数据的过程。
迭代器(Iterator):
- 为各种数据结构,提供了一个可以统一、简便的访问接口
- 使得数据结构的成员,能够按照某种顺序排列
Symbol.iterator为对象定义了迭代器,可以被for...of循环使用
1.当对象具有Symbol.iterator接口时,就可以使用for...of迭代对象
1.原生具备
Symbol.iterator接口的数据结构有:Array、Set、Map、String、arguments、NodeList
2.for...of是语法糖,本质上还是用的迭代器方法
const arr = [1, 3, 5, 7, 9];
console.log(arr);for (const i of arr) {console.log(i);
}
点击Array对象,展开[[Prototype]]: Array(0)以后,发现具有Symbol(Symbol.iterator) : ƒ values(),因此可以使用for...of遍历数组。

2.通过 Symbol.iterator 来创建迭代器
const arr = [1, 3, 5, 7, 9];
const iter = arr[Symbol.iterator](); // 创建迭代器console.log(iter.next()); // {value: 1, done: false}
console.log(iter.next()); // {value: 3, done: false}
console.log(iter.next()); // {value: 5, done: false}
console.log(iter.next()); // {value: 7, done: false}
console.log(iter.next()); // {value: 9, done: false}
console.log(iter.next()); // {value: undefined, done: true}
next方法返回一个对象,该对象包含两个属性:
- value:下一个数据的值
- done:已经迭代到序列中的最后一个值,为 true,否则为false
Iterator 的遍历过程:
- 创建一个指针对象,指向当前数据结构的起始位置。也就是说,迭代器对象本质就是一个指针对象。
- 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
- 第二次调用指针对象的next方法,可以将指针指向数据结构的第二个成员。
- 不断地调用指针对象的next方法,直到它指向数据结构的结束位置。
7.2 Generator
Generator(生成器)函数:
- 是一种异步编程解决方案
- 是一个状态机,封装了多个内部状态
- 执行Generator函数会返回一个遍历器对象,可以遍历每一个状态
1.next方法执行下一个状态,一个yield代表一个状态,碰到yield停下
function* gen() {console.log(10);yield;console.log(20);yield;console.log(30);
}const g = gen();
g.next(); // 10
g.next(); // 20
g.next(); // 30
2.yield可以跟返回的结果
function* gen() {console.log(10);yield "aaa";console.log(20);yield "bbb";console.log(30);return "ccc";
}const g = gen();
const res1 = g.next(); // 10
console.log(res1); // {value: 'aaa', done: false}const res2 = g.next(); // 20
console.log(res2); // {value: 'bbb', done: false}const res3 = g.next(); // 30
console.log(res3); // {value: ccc, done: true}
3.可以使用for...of进行遍历每个状态
function* gen() {console.log(10);yield "aaa";console.log(20);yield "bbb";console.log(30);return "ccc";
}const g = gen();
for (const i of g) {console.log(i);
}
4.通过next方法,可以传入参数到生成器函数
注:第一个next方法传入的参数不会生效
function* gen() {const res1 = yield;console.log(res1);const res2 = yield;console.log(res2);
}const g = gen();
g.next(10); // 无输出
g.next(20); // 20
g.next(30); // 30
分析:
1.执行第一个next时,碰到第一个yield停下来了,还没有执行赋值操作
2.执行第二个next时,将传入的参数20赋值给了res1,接着碰到第二个yield停下
3.执行第三个next时,将传入的参数30赋值给了res2,接着走到函数结束
8. Proxy和Reflect
8.1 Proxy
代理(Proxy ):作用是在对象和对象的属性值之间设置一个代理,获取该对象的值、设置该对象的值以及实例化等操作,都会被拦截住。经过这一层,我们可以统一处理,我们可以认为它就是代理器。
拦截:获取和修改数据时会进行拦截,用于脏数据检查。
1.es5 拦截方法:Object.defineProperty()
Object.defineProperty(obj, prop, descriptor):
obj:要被修改拦截的对象prop:要被修改拦截的属性descriptor:当访问属性时,会调用get函数;当属性值被修改时,会调用set函数。
缺点:
1.一次只能拦截一个属性
2.只能拦截对象
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><p>Hello World</p><script>const p = document.querySelector("p");const obj = {};// 为obj对象的data属性设置拦截Object.defineProperty(obj, "data", {get() {return p.innerHTML;},set(value) {p.innerHTML = value;}});</script></body>
</html>
分别输入obj.data、obj.data='aaa'、obj.data,触发 get、set 和 get, 运行结果如下:

2.es6 拦截方法:Proxy(target, handler)
Proxy(target, handler):
target:要被修改拦截的对象handler:执行各种操作时代理的行为
优点:
1.一次可以拦截多个属性
2.可以拦截任何类型的对象,包括数组、函数等
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><p>Hello World</p><script>const p = document.querySelector("p");const obj = {};// 为obj对象创建一个代理const proxy = new Proxy(obj, {get(target, key) {return target[key];},set(target, key, value) {// 访问data属性时,修改dom元素if (key === "data") {p.innerHTML = value;}target[key] = value;}});</script></body>
</html>
操作obj对象,运行结果如下:

操作proxy对象,运行结果如下:

8.2 Reflect
反射(Reflect):用于获取目标对象的行为,它与Object类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与proxy handlers 的方法相同。
1.代替Object的某些方法
const obj = {};
Reflect.defineProperty(obj, "name", {value: "Bill"
});
2.修改某些Object方法的返回结果
// Object.defineProperty返回值是对象,只能使用try...catch做异常处理
try {Object.defineProperty(target, property, attributes);// success
} catch (e) {// fail
}// Reflect.defineProperty方法的返回值为Boolean值,可以使用if...else做异常处理
if (Reflect.defineProperty(target, property, attributes)) {// success
} else {// fail
}
3.命令式写法改为使用函数写法
// 命令式写法
const obj = { name: "Bill" };
console.log("name" in obj); // true
delete obj.name;
// Reflect函数写法
const obj = { name: "Bill" };
console.log(Reflect.has(obj, "name")); // true
Reflect.deleteProperty(obj, "name");
4.配合Proxy使用,反射到代理对象原来的默认行为上
const s = new Set();
const proxy = new Proxy(s, {get(target, key) {const value = Reflect.get(target, key); // 等价于const value = target[key]// 判断如果是方法,修正this指向if (value instanceof Function) {return value.bind(target);}return value;},set(target, key, value) {Reflect.set(target, key, value); // 等价于target[key] = value}
});
注:还可以和扩展运算符配合使用,将以上的
get和set方法,改为Reflect.get(...arguments)和
Reflect.set(...arguments)
在控制台输入内容,运行结果如下:

9. Promise
Promise:是异步编程的一种解决方案,比传统的解决方案回调函数,更合理和更强大。
Promise的作用: 解决异步回调地狱的问题。
回调地狱:当一个回调函数嵌套一个回调函数的时候,就会出现一个嵌套结构,当嵌套多了就会出现回调地狱的情况。
例如发送三个ajax请求:
- 第一个正常发送
- 第二个请求需要第一个请求的结果中某一个值作为参数
- 第三个请求需要第二个请求的结果中某一个值作为参数
Promise的状态:
- 待定(pending):初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled):意味着操作成功完成。
- 已拒绝(rejected):意味着操作失败。
- 这三种状态的变化途径只有两种:从待定到已兑现、从待定到已拒绝。
- 一旦状态发生变化,就凝固了,不会再有新的状态变化,这是Promise(承诺)这个名字的由来,一旦承诺生效,就不能再改变了。
Promise构造器语法:
new Promise(executor)
1.Promise的基础示例
const promise = new Promise((resolve, reject) => {setTimeout(() => {resolve("success");}, 1000);
});promise.then(res => {console.log(res); // success
});
当执行了resolve方法,则会执行第一个回调函数then方法
2.异步操作成功执行resolve方法,然后回调then方法,异步操作失败执行reject方法,然后回调catch方法
1.resolve方法传入的参数,作为then方法的入参
2.reject方法传入的参数,,作为catch方法的入参
const promise = new Promise((resolve, reject) => {setTimeout(() => {resolve("success");reject("failed");}, 1000);
});promise.then(res => {console.log(res); // success}).catch(err => {console.log(err); // failed});
运行结果:

分析:先调用了 resolve 方法,导致状态从待定到已兑现,然后状态发生凝固,后续reject方法不再执行。
3.链式调用,解决回调地狱问题
链式调用图解:

const promise = new Promise((resolve, reject) => {setTimeout(() => {resolve("success");reject("failed");}, 1000);
});promise.then(res => {console.log(`first ${res}`); // first successreturn res;}).then(res => {console.log(`second ${res}`); // second success}).catch(err => {console.log(err);});
分析:
- 先调用了resolve,然后执行第一个then方法,promise对象的状态从待定到已兑现。
- 第一个then方法执行完成后,又返回了一个新的promise对象(同时返回值也会作为第二个then方法的入参),新的promise对象继续执行了第二个then方法,然后新promise对象的状态也从待定到已兑现。
4.Promise.all():等待所有传入的 promise 都变为完成状态后,再执行回调
const p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve(1000);}, 1000);
});const p2 = new Promise((resolve, reject) => {setTimeout(() => {resolve(2000);}, 2000);
});const p3 = new Promise((resolve, reject) => {setTimeout(() => {resolve(3000);}, 3000);
});// p1, p2, p3都执行了resolve后,调用then
Promise.all([p1, p2, p3]).then(res => {console.log(res); // [1000, 2000, 3000]}).catch(err => {console.log(err);});
5.Promise.race():所有传入的 promise 中,先变为完成状态的 promise 执行回调
// p1等待一秒,最先执行完毕
const p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve(1000);}, 1000);
});const p2 = new Promise((resolve, reject) => {setTimeout(() => {resolve(2000);}, 2000);
});const p3 = new Promise((resolve, reject) => {setTimeout(() => {resolve(3000);}, 3000);
});// p1, p2, p3第一个执行resolve的,调用then
Promise.race([p1, p2, p3]).then(res => {console.log(res); // 1000}).catch(err => {console.log(err);});
10. Async和Await
Async + Await是Promise + Generator的语法糖,它可以使得Promise的书写更为简单,可以使用同步的方式,来执行异步操作。
async 和 await:
- async 使函数返回 Promise
- await 使函数等待 Promise
10.1 Async
1.函数前加上关键字 async,使函数返回 promise 对象
async function fn() {return "Hello World"; // 等价于return Promise.resolve("Hello World");
}const res = fn();
console.log(res); // Promise {<fulfilled>: 'Hello World'}
2.return的值为promise对象时,异步操作成功执行resolve方法,然后回调then方法,异步操作失败执行reject方法,然后回调catch方法
1.resolve方法传入的参数,作为then方法的入参
2.reject方法传入的参数,,作为catch方法的入参
async function fn() {return new Promise((resolve, reject) => {resolve("success");// reject("failed");});
}const promise = fn();
promise.then(res => {console.log(res); // success}).catch(err => {console.log(err); // failed});
10.2 Await
await 使函数等待 promise
注:await 关键字只能在 async 函数中使用
1.不使用await,不会等待promise
function fn() {return new Promise((resolve, reject) => {setTimeout(() => {console.log(1);resolve(2);}, 2000);});
}// 不使用await
async function test() {const res = fn();console.log(res); console.log(3);
}test();
运行结果:

分析:
1.未使用await,因为setTimeout是异步的,setTimeout的回调函数还未执行,那么resolve也还没执行到,就已经把promise对象返回了,因此打印出来的res是一个还在pending状态的promise对象。
2.因为setTimeout是异步的,没有阻塞后续代码的执行,所以先打印了3。
3.两秒钟结束后,执行setTimeout的回调函数,打印了1,再执行了resolve方法。
2.使用await,会等待promise返回
function fn() {return new Promise((resolve, reject) => {setTimeout(() => {console.log(1);resolve(2);}, 2000);});
}// 使用await
async function test() {const res = await fn();console.log(res);console.log(3);
}test();
运行结果:

分析:
1.使用了await,会一直等待promise返回,直到resolve方法执行后,再执行后续代码,因此先执行了setTimeout的回调函数(因为resolve方法在该回调函数中),打印了1
2.执行了resolve,将resolve的结果,返回给res,打印了2
3.再执行后续代码,最后打印了3
3.使用await,只会等待promise,而不会等待其他的异步
以下代码,使用了await,并不会等待setTimeout先执行回调函数,因为resolve不在setTimeout的回调函数中
function fn() {return new Promise((resolve, reject) => {setTimeout(() => {console.log(1);}, 2000);resolve(2); // 不把resolve放在setTimeout回调函数内});
}// 使用await
async function test() {const res = await fn();console.log(res);console.log(3);
}test();
运行结果:

分析:
1.调用fn时,先执行到了setTimeout,由于它是异步的,其回调函数没有先执行
2.然后执行了resolve方法,将结果返回给了res,打印了2
3.再执行后续代码,最后打印了3
4.两秒钟结束后,执行setTimeout的回调函数,打印了1
11. 类
类:类不是对象,而是对象的模板
11.1 类的定义和使用
类的语法:
class ClassName {constructor() { ... }method_1() { ... }method_2() { ... }method_3() { ... }
}
1.类的定义和使用
- 使用关键字
class创建一个类 - 通过构造方法
constructor()给属性赋值 - 创建类方法的语法与对象方法相同
构造方法:
1.创建对象时会自动调用构造方法
2.构造方法用于初始化对象属性
3.如果没有定义构造方法,JS 会添加一个空的构造方法
// 类的定义
class Person {// 构造方法constructor(name, age) {this.name = name;this.age = age;}// 类方法say() {console.log(this.name, this.age);}
}const person = new Person("Bill", 18); // 使用类来创建对象
console.log(person.name); // Bill
console.log(person.age); // 18
person.say(); // Bill 18
2.类可以使用 getter 和 setter
- 在类中添加 getter 和 setter,请使用
get和set关键字 - getter/setter 的方法名不能与属性名相同
- 建议使用下划线字符将 getter/setter 与实际属性分开
class Person {constructor(name, age) {this._name = name;this._age = age;}// getterget getName() {return this._name;}// setterset setName(x) {this._name = x;}
}const person = new Person("Bill", 18);
console.log(person.getName); // Bill
person.setName = "Jackson";
console.log(person.getName); // Jackson
11.2 类的继承
类继承:使用类继承创建的类,继承了另一个类的所有方法
1.使用关键字 extends来继承类
super()方法引用父类:
1.在constructor方法中调用super方法,则调用了父类的 constructor 方法,获得了父级的属性和方法的访问权限
2.在类方法中调用super方法,则调用了父类的类方法
// 创建一个Person类
class Person {constructor(name, age) {this.name = name;this.age = age;}say() {console.log(this.name, this.age);}
}// 创建一个Student类,继承了Person类
class Student extends Person {constructor(name, age, score) {super(name, age); // 调用父类的constructor方法this.score = score;}
}const student = new Student("Bill", 18, 90);
student.say(); // 调用父类的方法
2.重写方法
- 当子类的方法名与父类的方法名一致时,子类的方法会覆盖父类的方法
- 子类的对象调用该方法时,调用的是子类的方法,而不会调用父类的方法
// 创建一个Person类
class Person {constructor(name, age) {this.name = name;this.age = age;}say() {console.log(this.name, this.age);}
}// 创建一个Student类,继承了Person类
class Student extends Person {constructor(name, age, score) {super(name, age);this.score = score;}// 重写父类的方法say() {console.log(`${this.name}: age is ${this.age}, score is ${this.score}`);}
}const student = new Student("Bill", 18, 90);
student.say(); // Bill: age is 18, score is 90
12. 模块
模块:一个模块(module)就是一个js文件,可以通过export和import命令来实现两个模块之间的交互,也就是一个js文件可以引用另一个js文件的内容。
export:表示当前模块的变量和函数可以被外部访问import:导入了其它模块的变量和函数到当前模块
注:以前使用
<script src="xxx.js"></script>的方式来引用js文件,会带来一些问题(如引用的两个js文件有函数名和变量名相同),而通过模块化可以解决这些问题。
12.1 export
1.定义变量和函数的同时就导出
export const name = "Bill";
export const age = 18;export function fn() {console.log("Hello World");
}
2.定义变量和函数后再导出
const name = "Bill";
const age = 18;function fn() {console.log("Hello World");
}export { name, age, fn };
3.使用as关键字,可以给导出的变量和函数取别名
注:导出的时候取了别名的话,导入时也需要使用导出时的别名
const name = "Bill";
const age = 18;function fn() {console.log("Hello World");
}export { name as gName, age as gAge, fn as gFn };
4.export default默认导出
- 一个模块中,只能有一个
export default - 默认导出时可以不需要指定名字
- 导入时不需要使用
{},并且可以自己来指定名字
// 默认导出变量
const name = "Bill";
export default { name };
// 默认导出函数
export default function fn() {console.log("Hello World");
}
12.2 import
准备一个test.js文件,用于导出变量和函数,内容如下:
const name = "Bill";
const age = 18;function fn() {console.log("Hello World");
}export { name, age, fn };
1.在js文件中导入另一个js文件
在test.js同级目录下,新建一个demo.js,内容如下:
import { name, age, fn } from "./test.js";console.log(name, age); // Bill 18
fn(); // Hello World
2.在html文件中导入另一个js文件
注:html文件导入js文件时,要设置
script标签的属性type="module",否则会报错
在test.js同级目录下,新建一个demo.html,内容如下:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><script type="module">// 导入test.jsimport { name, age, fn } from "./test.js";console.log(name, age); // Bill 18fn(); // Hello World</script></body>
</html>
3.使用as关键字,可以给导入的变量和函数取别名
import { name as gName, age as gAge, fn as gFn } from "./test.js";console.log(gName, gAge);
gFn();
4.使用*和 as,可以把所有导入变量和函数指定到一个模块对象上
注:使用这种方式导入时,要去掉
{}
import * as obj from "./test.js";console.log(obj.name, obj.age);
obj.fn();相关文章:
ES6新特性详解
文章目录1. let和const1.1 let声明变量1.2 const声明常量2. 模板字符串3. 解构赋值3.1 数组的解构赋值3.2 对象的解构赋值4. 函数扩展4.1 参数默认值4.2 剩余参数4.3 箭头函数5. 对象扩展5.1 对象简写5.2 属性名表达式5.3 扩展运算符6. Symbol7. Iterator和Generator7.1 Iterat…...
Ubuntu下安装 ntfs-3g
目录1.FAT32、NTFS和exFAT2.ubuntu 安装 ntfs-3g2.1 直接安装2.2 源码安装1.FAT32、NTFS和exFAT U盘在格式化的时候都会有三种格式分别是FAT32、NTFS和exFAT。 FAT32格式 FAT32格式硬盘分区的最大容量为2TB,虽然U盘做不到,但是现在1xTB硬盘都有了&…...
【专业认知】抖音就业 / 保研北大教育学 / 留学南加州EE / 微软就业
2023.2.18 一. 周金辉学长分享——本科经验分享 0 简介 计算机农大本硕 硕士毕业后在抖音公司工作 1 行业前景:计算机专业能做什么? 1.1 计算机行业发展路线 远古时代: 二战开始,计算机技术发展,出现互联网 包…...
【算法题】2 的 n 次幂的背后
前言: 说实话,真的不爱写算法题相关的文章了,觉得没啥意义,但是对这种比较好玩并且简单,学会了就能很好提高算法效率的文章,还是要写一写,不哭不哭,你不会不是你的错,只是…...
【人工智能AI】一、NoSQL 企业级基础入门《NoSQL 企业级基础入门与进阶实战》
写一篇介绍什么是NoSQL的技术文章,分5个章节,每个章节细分到3级目录,重点介绍一下优缺点,适用场景,未来发展趋势等。 一、NoSQL简介 1.1 什么是NoSQL NoSQL(Not only SQL),意思是“…...
Ubuntu安装opencv库3.4.10,并在cmake工程中引入opencv库
Windows下安装不同,Ubuntu安装OpenCV库时,需要事先安装依赖,而且不同OpenCV库所需的依赖可能会有所不同,下面的依赖亲测 3.4.10 和 4.5.5版本的有效,但是4.6以上版本安装可能会报错。 参考链接:https://bl…...
实现8086虚拟机(四)——mov 和 jmp 指令解码
文章目录mov 指令解码jmp 指令解码这篇文章举例来讲讲 mov 指令和 jmp 指令解码函数的实现,其他的指令解码函数都与这些类似。mov 指令解码 以 mov 指令中的一类:寄存器/内存 到/从 寄存器,来详细说明解码函数的实现。 机器指令格式如下&am…...
数据库技术-函数依赖、键与约束、范式
一、函数依赖 给定一个x,能唯一确定一个Y,就称x确定Y,或者说Y依赖于x,例如YX*X函数。 函数依赖又可扩展以下两种规则: 部分函数依赖:A可确定C,(A,B)也可确定C,(A,B)中的一部分(即A)可以确定C&a…...
shiro CVE-2020-1957
0x00 前言 在之前只是单纯的复现了漏洞,没有记笔记,所以补充了这篇分析笔记。 影响版本:shiro < 1.5.2 0x01 环境搭建 环境用的是:https://github.com/lenve/javaboy-code-samples/tree/master/shiro/shiro-basic 0x02 漏…...
RabbitMQ 入门到应用 ( 五 ) 基本应用
6.更多应用 6.1.AmqpAdmin 工具类 可以通过Spring的Autowired 注入 AmqpAdmin 工具类 , 通过这个工具类创建 队列, 交换机及绑定 import org.springframework.amqp.core.AmqpAdmin; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.Di…...
部署dapr的辛酸历程
前言dapr大概的了解,个人理解他就是一个分布式服务的管理,把微服务常用的组件(缓存,消息中间件、分布式锁、安全id4等)和监控以及服务注册、发现等等一系列功能以一个很抽象的方式管理起来。可能我们部署微服务用consul、ocelot、polly套件、…...
golang入门笔记——内存管理
文章目录自动内存管理概念自动内存管理-相关概念:追踪垃圾回收:分代GC(Generational GC)引用计数内存分配Go内存分配-分块Go内存分配——多级缓存Go内存管理优化Balanced GC自动内存管理 概念 1.动态内存 程序在运行时根据需求…...
97. 约数之和
Powered by:NEFU AB-IN Link 文章目录97. 约数之和题意思路代码97. 约数之和 题意 假设现在有两个自然数 A和 B,S是 A^B的所有约数之和。 请你求出 S mod 9901的值是多少。 思路 ABA^BAB的约数之和为:sumAB(1p1p12...p1Ba1)(1p2p22...p2Ba2)...sum_{A^B…...
想和20岁的自己说
男生床头千万不要放卫生纸不要叫自己的女朋友早睡,更不能叫她早起,否则有你好受的。成年人的默契:和异性单独出去旅游,如果没有明确拒绝开一间房,那基本上默认后面会发生的事情不要去考验人性,世上99%的人经…...
Unit Test and Integration Test
Unit Test and Integration Test Background It is the first time that I try to write an article in English. In the past, I didn’t write test code. Just thinking QA is responsible for testing. As a developer, I don’t need to care about tests. Although I …...
2022年全国职业院校技能大赛(中职组)网络安全竞赛试题(3)
目录 模块A 基础设施设置与安全加固 (本模块20分) 一、项目和任务描述: 假定你是某企业的网络安全工程师,对于企业的服务器系统,根据任务要求确保各服务正常运行,并通过综合运用用户安全管理与密码策略、…...
智慧城市应急指挥中心数字化及城市驾驶舱建设方案
目 录 第一章 项目概述 1.1 项目背景 1.2 项目范围 第二章 建设内容 2.1 三维可视化平台 2.1.1 多源数据接入 2.1.2 可视化编排 2.1.3 三维可视化编辑 2.1.4 空间数据可视化 2.1.5 集成框架支持 2.2 可视化场景定制开发 2.2.1 城市驾驶总舱 2.2.2 城市安全分舱 2.…...
HSCSEC 2023 个人练习
😋 大家好,我是YAy_17,是一枚爱好网安的小白。本人水平有限,欢迎各位大佬指点,欢迎关注😁,一起学习 💗 ,一起进步 ⭐ 。⭐ 此后如竟没有炬火,我便是唯一的光。…...
Android 基础知识4-2.7 RelativeLayout(相对布局)
一、RelativeLayout的概述 RelativeLayout(相对布局)是一种根据父容器和兄弟控件作为参照来确定控件位置的布局方式。在很多时候,线性布局还不能满足我们的需求,比如,我们在一行(列)上显示多个控…...
关于云计算,我们问了ChatGPT 10个问题
ChatGPT懂云计算吗?前些天,我们问了ChatGPT(非Plus收费版)一些问题。1. 什么是云计算?2. 云计算行业的护城河是什么?3. 什么是云原生?4. 微软Azure与亚马逊AWS的主要区别是什么?5. 为…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
