2.10、rest参数
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments
javascript
<script>
// ES5 获取实参的方式
/* function date(){
console.log(arguments);
}
date('大白','二黑','三孩'); */
// rest 参数
/* function date(...args) {
console.log(args); // filter some every map
}
date("大白", "二黑", "三孩"); */
// rest 参数必须要放到参数最后
/* function fn(a,b,...args){
console.log(a);
console.log(b);
console.log(args);
}
fn(1,2,3,4,5,6); */
</script>
注意:rest 参数非常适合不定个数参数函数的场景
2.11、Symbol
2.11.1、Symbol 基本使用
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
undefined、string、 symbol 、object 、null 、number 、boolean
Symbol 特点
-
Symbol 的值是唯一的,用来解决命名冲突的问题
-
Symbol 值不能与其他数据进行运算
-
Symbol 定义的对象属性不能使用 for...in 循环遍历 ,但 是可以使用Reflect.ownKeys 来获取对象的所有键名
注: 遇到唯一性的场景时要想到 Symbol
javascript
<script>
//创建方式
//创建Symbol方式1
let s = Symbol();
// console.log(s, typeof s);
//创建方式2
// Symbol()函数可以接受一个字符串作为参数,
// 表示对 Symbol 实例的描述。这主要是为了在控制台显示,比较容易区分。
let s2 = Symbol('bdqn');//'bdqn'这个内容只是个标识
let s3 = Symbol('bdqn');
console.log('s2===s3',s2===s3);//false
// 创建方式3 Symbol.for
// Symbol.for并不是每次都会创建一个新的symbol,它会先检索symbol表中是否有,没有再创建新的,有就返回上次存储的
let s4 = Symbol.for('bdqn');
let s5 = Symbol.for('bdqn');
console.log('s4===s5',s4===s5);//true
//注意事项
//1:不能与其他数据进行运算
// let result = s + 100;
// let result = s > 100;
// let result = s + s;
</script>
2.11.2、Symbol创建对象属性
可以给对象添加属性和方法
javascript
<script>
//向对象中添加方法 up down
let game = {
name: "俄罗斯方块",
up: function () {},
down: function () {},
};
//声明一个对象
/* let methods = {
up: Symbol(),
down: Symbol(),
};
game[methods.up] = function () {
console.log("我可以改变形状");
};
game[methods.down] = function () {
console.log("我可以快速下降!!");
};
console.log(game); */
let youxi = {
name:"狼人杀",
[Symbol('say')]: function(){
console.log("我可以发言")
},
[Symbol('zibao')]: function(){
console.log('我可以自爆');
}
}
console.log(youxi);
</script>
2.11.3、Symbol的内置对象
除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行。
|---------------------------|----------------------------------------------------------------------------------|
| Symbol.hasInstance | 当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法 |
| Symbol.isConcatSpreadable | 对象的Symbol.isConcatSpreadable属性等于的是一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开。 |
| Symbol.species | 创建衍生对象时,会使用该属性 |
| Symbol.match | 当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值。 |
| Symbol.replace | 当该对象被str.replace(myObject)方法调用时,会返回该方法的返回值。 |
| Symbol.search | 当该对象被str.search(myObject)方法调用时,会返回该方法的返回值。 |
| Symbol.split | 当该对象被str.split(myObject)方法调用时,会返回该方法的返回值。 |
| Symbol.iterator | 对象进行for...of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器 |
| Symbol.toPrimitive | 该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。 |
| Symbol.toStringTag | 在该对象上面调用toString方法时,返回该方法的返回值 |
| Symbol.unscopables | 该对象指定了使用with关键字时,哪些属性会被with环境排除。 |
2.12、迭代器
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。(Iterator 接口就是对象里面的一个属性)
Iterator 接口就是对象的一个属性
Iterator 的作用有三个:
一是 为各种数据结构,提供一个统一的、简便的访问接口;
二是 使得数据结构的成员能够按某种次序排列;
三是 ES6 创造了一种新的遍历命令for...of 循环,Iterator 接口主要供for...of循环
-
ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费
-
原生具备 iterator 接口的数据(可用 for of 遍历)
a) Array
b) Arguments
c) Set
d) Map
e) String
f) TypedArray
g) NodeList
- 工作原理
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。
(5) 每调用 next 方法返回一个包含 value 和 done 属性的对象
done:是否循环完毕
**注:**迭代器就是按照一定的顺序对元素进行遍历的过程
javascript
<script>
//声明一个数组
const xiyou = ["唐僧", "孙悟空", "猪八戒", "沙僧"];
//使用 for...of 遍历数组
for (let v of xiyou) {
console.log(v);
}
let iterator = xiyou[Symbol.iterator]();
console.log(iterator);
//调用对象的next方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
</script>
2.13、生成器
Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
Generator 函数是一个状态机,封装了多个内部状态。
执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。
2.13.1、生成器基本语法
通过function关键字后的星号(*)来表示,函数中会用到新的关键字yield。星号(*)可以紧挨着function关键字,也可以在中间添加一个空格
javascript
<script>
//生成器其实就是一个特殊的函数
//异步编程 纯回调函数 node fs ajax mongodb
//yield 函数代码的分隔符,分割代码
function* cook() {
let i = 1;
console.log(`我被执行了${i}次`);
yield "盛米";
i++;
console.log(`我被执行了${i}次`);
yield "淘米";
i++;
console.log(`我被执行了${i}次`);
yield "煮米";
i++;
console.log(`我被执行了${i}次`);
}
let iterator = cook(); //返回一个迭代器对象,里面有个next()方法
//函数不会一下子执行完毕,会以yield为分割线,调一次next,执行一次
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
//遍历
// for(let v of cook()){
// console.log(v);
// }
</script>
代码说明:
-
cook()前的星号 * 表明它是一个生成器
-
生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到yield 语句后的值
-
yield 相当于函数的暂停标记,每当执行完一条yield语句后函数就会自动停止执行,也可以认为是函数的分隔符,每调用一次 next方法,执行一段代码
-
next 方法可以传递实参,作为 yield 语句的返回值
5)yield关键字只可在生成器内部使用,在其他地方使用会导致程序抛出错误
2.13.2、生成器函数参数
**概念:**next('BBB')传入的参数作为上一个next方法的返回值。
javascript
<script>
function * gen(arg) {
console.log(arg);//AAA
let one = yield "aaa";
console.log(one);//BBB
let two = yield "bbb";
console.log(two);//CCC
let three = yield "ccc";
console.log(three);//DDD
}
//执行获取迭代器对象
let iterator = gen("AAA ");
console.log(iterator.next()); //{value: 'aaa', done: false}
//next方法可以传入的实参,作为yield语句整体返回的结果
console.log(iterator.next("BBB"));
console.log(iterator.next("CCC"));
console.log(iterator.next("DDD"));
</script>
2.13.3、生成器函数实例
javascript
<script>
// 异步编程 文件操作 网络操作(ajax, request) 数据库操作
// 需求:1s 后控制台输出 111 2s后输出 222 3s后输出 333
// 回调地狱(一层套一层,不停回调)
/* setTimeout(() => {
console.log(111);
setTimeout(() => {
console.log(222);
setTimeout(() => {
console.log(333);
}, 3000);
}, 2000);
}, 1000); */
// 生成器函数解决回调地域
//生成3个异步函数
function one() {
setTimeout(() => {
console.log(111);
iterator.next(); //函数one执行完毕后,调用next(),执行下一个异步函数
}, 1000);
}
function two() {
setTimeout(() => {
console.log(222);
iterator.next(); //函数two执行完毕后,调用next(),执行下一个异步函数
}, 2000);
}
function three() {
setTimeout(() => {
console.log(333);
iterator.next(); //函数three执行完毕后,调用next(),执行下一个异步函数
}, 3000);
}
//用生成器函数将三个异步函数放在yield语句中
function* gen() {
yield one();
yield two();
yield three();
}
//调用生成器函数
let iterator = gen();
iterator.next(); //调用一次next执行一个yield语句,这个只会执行one()回调
</script>
2.14、Promise
2.14.0、回调地狱
回调地狱:就是回调函数嵌套过多导致的
- 当一个回调函数嵌套一个回调函数的时候
- 就会出现一个嵌套结构
- 当嵌套的多了就会出现回调地狱的情况
- 比如我们发送三个 ajax 请求
-
- 第一个正常发送
- 第二个请求需要第一个请求的结果中的某一个值作为参数
- 第三个请求需要第二个请求的结果中的某一个值作为参数
javascript
<script>
function fn() {
setTimeout(function () {
console.log("111");
setTimeout(function () {
console.log("222");
setTimeout(function () {
console.log("333");
}, 1000);
}, 2000);
}, 3000);
}
fn();
</script>
2.14.1、什么是promise
Promise是ES6异步编程的一种解决方案(目前最先进的解决方案是async和await的搭配(ES8),但是它们是基于promise的)
从语法上讲,Promise是一个对象或者说是构造函数,用来封装异步操作并可以获取其成功或失败的结果。
2.14.2、Promise对象的状态:
2.14.2.1、对象的状态不受外界影响。
Promise 对象通过自身的状态,来控制异步操作。Promise 实例具有三种状态。
- pending: 等待中,或者进行中,表示还没有得到结果
- resolved(Fulfilled): 已经完成,表示得到了我们想要的结果,可以继续往下执行
- rejected: 也表示得到结果,但是由于结果并非我们所愿,因此拒绝执行
2.14.2.2、Promise对象三种状态不受外界影响,三种的状态的变化途径只有两种。
- 从"未完成"到"成功"
- 从"未完成"到"失败"
一旦状态发生变化,就凝固了,不会再有新的状态变化。这也是 Promise 这个名字的由来,它的英语意思是"承诺",一旦承诺成效,就不得再改变了。这也意味着,Promise 实例的状态变化只可能发生一次。
2.14.2.3、Promise 的最终结果只有两种。
- 异步操作成功,Promise 实例传回一个值(value),状态变为fulfilled。
- 异步操作失败,Promise 实例抛出一个错误(error),状态变为rejected。
2.14.3、Promise语法格式
javascript
//写法一
new Promise(function (resolve, reject) {
// resolve 表示成功的回调
// reject 表示失败的回调
}).then(function (res) {
// 成功的函数
}).catch(function (err) {
// 失败的函数
})
//写法二
new Promise(function (resolve, reject) {
// resolve 表示成功的回调
// reject 表示失败的回调
}).then(function (res) {
// 成功的函数
},function(res){
// 失败的函数
})
出现了new关键字,就明白了Promise对象其实就是一个构造函数,是用来生成Promise实例的。能看出来构造函数接收了一个函数作为参数,该函数就是Promise构造函数的回调函数,该函数中有两个参数resolve和reject,这两个参数也分别是两个函数!
简单的去理解的话
resolve函数的目的是将Promise对象状态变成成功状态,在异步操作成功时调用,将异步操作的结果,作为参数传递出去。
reject函数的目的是将Promise对象的状态变成失败状态,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。
注意:then方法可以接受两个函数 ,第一个函数为 promise状态为成功的回调函数 ,第二个函数为 promise状态为失败的回调函数 ( 可以不写,一般用catch方法捕获promise状态为失败的异常信息)
2.14.4、代码示例
javascript
const promise = new Promise((resolve,reject)=>{
//异步代码
setTimeout(()=>{
// resolve(['111','222','333'])
reject('error')
},2000)
})
//写法一
promise.then((res)=>{
//兑现承诺,这个函数被执行
console.log('success',res);
}).catch((err)=>{
//拒绝承诺,这个函数就会被执行
console.log('fail',err);
})
//写法二
promise.then(
function (value) {
console.log(value);
},
function (reason) {
console.error(reason);
}
);
2.14.5、Promise封装Ajax
javascript
<script>
// 接口地址: https://api.apiopen.top/getJoke
const p = new Promise((resolve, reject) => {
//1. 创建对象
const xhr = new XMLHttpRequest();
//2. 初始化
xhr.open("GET", "https://api.apiopen.top/getJoke");
//3. 发送
xhr.send();
//4. 绑定事件, 处理响应结果
xhr.onreadystatechange = function () {
//判断
if (xhr.readyState === 4) {
//判断响应状态码 200-299
if (xhr.status >= 200 && xhr.status < 300) {
//表示成功
resolve(xhr.response);
} else {
//如果失败
reject(xhr.status);
}
}
};
});
//指定回调
p.then(
function (value) {
console.log(value);
},
function (reason) {
console.error(reason);
}
);
</script>
2.14.6**、promise的对象方法**
p1,p2,p3为promise的实例对象
2.14.6.1、Promise.then()方法
then方法的返回结果是 Promise 对象, 返回对象状态由回调函数的执行结果决定,结果有以下:
a. 如果回调函数中返回的结果是 非 promise 类型的属性,状态为成功, 返回值为对象的成功的值
b. 是 promise 对象,内部返回的状态,就是它的状态
c. 抛出错误 返回失败的promise状态
链式调用 可以改变回调地狱的情况
javascript
<script>
//创建 promise 对象
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("用户数据");
// reject('出错啦');
}, 1000);
});
const result = p.then(
(value) => {
console.log(value);
//1. 非 promise 类型的属性
// return 'iloveyou';
//2. 是 promise 对象
// return new Promise((resolve, reject)=>{
// // resolve('ok');
// reject('error');
// });
//3. 抛出错误
// throw new Error('出错啦!');
throw "出错啦!";
},
(reason) => {
console.warn(reason);
}
);
//链式调用
p.then(value=>{}).then(value=>{});
</script>
2.14.6.2、Promise.catch()
一般用catch方法捕获promise状态为失败的异常信息
javascript
<script>
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
//设置 p 对象的状态为失败, 并设置失败的值
reject("出错啦!");
}, 1000)
});
// p.then(function(value){}, function(reason){
// console.error(reason);
// });
p.catch(function(reason){
console.warn(reason);
});
</script>
2.14.6.3、Promise.all()
并发处理多个异步任务,所有任务都执行完成才能得到结果
javascript
Promise.all( [p1,p2,p3] ) .then ( (result) => {consoleog (result)
})
2.14.6.3、Promise.race()
只返回异步任务数组中第一个执行完的结果,其他任务仍在执行,不过结果会被抛弃
应用场景:
几个接口返回一样的数据,哪个快用哪个
javascript
Promise.race ( [p1,p2] ).then ( (result)=>{
console. log (result)
})
2.15、set
2.15.1、set基本知识
ES6 提供了新的数据结构Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for...of...』进行遍历
2.15.1.1、实例的属性和方法
- size:返回Set实例的成员总数。
- Set.prototype.add(value):添加某个value。
- Set.prototype.delete(value):删除某个value,返回一个布尔值,表示删除是否成功。
- Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
- Set.prototype.clear():清除所有成员,没有返回值。
javascript
<script>
//声明一个 set
let s = new Set();
let s2 = new Set(['张三','李四','王五','赵六']);
//元素个数
// console.log(s2.size);
//添加新的元素
// s2.add('jack');
//删除元素
// s2.delete('李四');
//检测
// console.log(s2.has('王五'));
//清空
// s2.clear();
// console.log(s2);
//遍历元素
for(let v of s2){
console.log(v);
}
</script>
2.15.1.2、set遍历
- Set.prototype.keys():返回键名的遍历器
- Set.prototype.values():返回键值的遍历器
- Set.prototype.entries():返回键值对的遍历器
- Set.prototype.forEach():遍历每个成员
javascript
let arr = new Set(["red", "green", "blue"]);
// 返回键名
for (let item of arr.keys()) {
// console.log(item);//red green blue
}
// 返回键值
for (let item of arr.values()) {
// console.log(item);//red green blue
}
// set 键名=键值
// 返回键值对
for (let item of arr.entries()) {
// console.log(item);// ['red', 'red'] ['green', 'green'] ['blue', 'blue']
}
// set也有forEach()方法
arr.forEach((value, key) => console.log(key + " : " + value));
2.15.2、set实践
javascript
<script>
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
//1. 数组去重
// let result = new Set(arr);
// result = [...result];
// console.log(result);
//2. 交集
let arr2 = [4, 5, 6, 5, 6];
/* 可以先去重,避免做无用对比 */
// let result = [...new Set(arr)].filter(item => {
// let s2 = new Set(arr2);//数组2去重后的结果 4 5 6
// if(s2.has(item)){
// return true;
// }else{
// return false;
// }
// });
//简化版本
// let result = [...new Set(arr)].filter((item) => new Set(arr2).has(item));
//console.log(result);
//3. 并集
// let union = [...new Set([...arr, ...arr2])];
// console.log(union);
//4. 差集
// let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
// console.log(diff);
</script>
2.16、Map
ES6 提供了 Map数据结构。它类似于对象,也是键值对的集合。但是"键"的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for...of...』进行遍历。
Map 的属性和方法:
-
size 返回 Map 的元素个数
-
set 增加一个新元素,返回当前 Map
-
get 返回键名对象的键值
-
has 检测 Map 中是否包含某个元素,返回 boolean 值
-
clear 清空集合,返回 undefined
javascript
<script>
/* map升级后的对象,键名可以是对象 */
//声明 Map
let m = new Map();
//添加元素 set()
m.set('name','bdqn');//键名:字符串
m.set('change', function(){//键名:字符串
console.log("我们可以改变你!!");
});
let key = {
school : '北京大学'
};
m.set(key, ['北京','上海','深圳']);//键名:对象
//size
// console.log(m.size);
//删除
// m.delete('name');
//获取 get()
// console.log(m.get('change'));
// console.log(m.get(key));
//清空 clear()
// m.clear();
//遍历
// for(let v of m){
// console.log(v);
// }
console.log(m);
</script>
2.17、class类
JavaScript 语言中,生成实例对象的传统方法是通过构造函数,ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
2.17.1、class初体验
javascript
<script>
// //es5通过构造函数实现
// function PersonO(username, password) {
// this.username = username;
// this.password = password;
// }
// // 添加方法
// PersonO.prototype.getstr = function () {
// console.log("用户名:" + this.username + ",密码:" + this.password);
// };
// // 实例化对象
// const po1 = new PersonO("章三", "abc123");
// console.log(po1);
// po1.getstr();
// es6实现 class方法实现
class PersonN {
//构造方法 constructor名字不能修改
// 当我们new实例对象的时候,这个方法自动执行
constructor(username, password) {
this.username = username;
this.password = password;
}
//方法必须使用该语法, 不能使用 ES5 的对象完整形式
getstr() {
console.log("用户名:" + this.username + ",密码:" + this.password);
}
//ES5 的对象完整形式 报错
// getstr:function () {}
}
const pn1 = new PersonN("123456", "789012");
pn1.getstr();
</script>
说明:使用class关键词 声明类,constructor为构造方法,一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加,
this关键字则代表实例对象,
getstr()为普通方法,不要用es5完整写法,getstr()存在 prototype上。
pn1.constructor === pn1.prototype.constructor // true
2.17.2 类的静态成员
es5可以直接给构造函数添加属性,方法,这些属性方法不在这个构造函数实例的对象身上
对应的es6中,类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为"静态方法"
javascript
<script>
// es5
function Phone() {}
// 给Phone添加静态属性
Phone.name = "手机";
Phone.call = function () {
console.log("我可以打电话");
};
//实例化对象
let apple = new Phone();
// console.log(apple.name); //undefined
//apple.change(); //报错 实例身上是没有构造函数身上的属性和方法
// Phone.call(); //我可以打电话
class PhoneN{
static name='手机'
static game(){
console.log('我可以打游戏');
}
}
let p1=new PhoneN()
console.log(p1.name);//undefined
console.log(PhoneN.name);//手机
</script>
2.17.3 类的继承
2.17.3.1、es5的继承
javascript
<script>
//手机 父级构造函数
function Phone(brand, price) {
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function () {
console.log("我可以打电话");
};
//智能手机 子级构造函数
function SmartPhone(brand, price, color, size) {
//通过call方法改变this指向,指向SmartPhone的实例对象
Phone.call(this, brand, price);
//子类独有的属性
this.color = color;
this.size = size;
}
//设置子级构造函数的原型 让SmartPhone的实例对象有父类的属性方法
SmartPhone.prototype = new Phone();
SmartPhone.prototype.constructor = SmartPhone;
//声明子类的方法
SmartPhone.prototype.photo = function () {
console.log("我可以拍照");
};
SmartPhone.prototype.playGame = function () {
console.log("我可以玩游戏");
};
//实例化对象
const chuizi = new SmartPhone("锤子", 2499, "黑色", "5.5inch");
console.log(chuizi);
</script>
2.17.3.2、es6的继承
javascript
<script>
// 定义父类
class Student {
//构造方法
constructor(realname, age) {
this.realname = realname;
this.age = age;
}
//父类的成员属性
play(str) {
console.log("我会玩" + str);
}
}
//定义子类
class ItStudent extends Student {
//构造方法
constructor(realname, age, major) {
//调用父类的方法,相当于Student.call(this,realname, age)
super(realname, age);
this.major = major;
}
//子类的成员属性
program(type) {
console.log("我会编程的语言是:" + type);
}
// 子类对父类方法的重写
play(str) {
console.log("我只学习,不玩" + str);
}
}
//实例化对象
const It1 = new ItStudent("张三", 20, "大数据");
console.log(It1.realname);
It1.play("游戏"); //我只学习,不玩游戏
</script>
说明:Class 可以通过extends关键字实现继承,让子类继承父类的属性和方法。ES6 规定,子类必须在constructor()方法中调用super(),否则就会报错。
2.17.4、getter和setter设置
javascript
<script>
// get 和 set
class Phone {
// get 监测动态属性的变化
get price() {
console.log("价格属性被读取了");
return "iloveyou";
}
// set 对更改设置的值做判断,合法怎么办,不合法怎么办
set price(newVal) {
console.log("价格属性被修改了");
}
}
//实例化对象
let s = new Phone();
console.log(s.price);//输出price属性,只要读取,就会执行get后面对应的函数代码,函数的返回值就是属性的返回值
s.price = "9.9";//更改price属性,只要更改,就会执行set后面对应的函数代码
</script>
2.18、模块化( module )
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
2.18.1、模块化的优势
-
防止命名冲突
-
代码复用
-
高维护性,可以对某些模块化升级
2.18.2、ES6 模块化语法
模块功能主要由两个命令构成:export 和 import。
export 命令用于规定模块的对外接口,对外暴露
import 命令用于输入其他模块提供的功能 ,引入暴露的文件
注意:
1、用了es6的语法, 浏览器默认将它作为js解析会出现问题,需要将它作为模块导入,script
标签默认type="text/javascript"
,需要改为type="module"
,更改后的index.html
:
2、跨域请求只支持这些协议:http, data, chrome, chrome-extension, chrome-untrusted, https.,而我们的协议是file,这里我们需要本地起一个服务器来作为资源的提供方,简单的方式是安装VSCode的一个扩展Live Server
2.18.2.1、暴露语法汇总
2.18.2.1.1、分别暴露
javascript
//m1.js 分别暴露
export let school = 'bdqn';
export function teach() {
console.log("我们可以教给你开发技能");
}
2.18.2.1.2、统一暴露
javascript
// m2.js 统一暴露
let school = 'bdqn';
function findJob(){
console.log("我们可以帮助你找工作!!");
}
export {school, findJob};
2.18.2.1.3、默认暴露
javascript
//m3.js 默认暴露
export default {
school: 'bdqn',
change: function(){
console.log("我们可以改变你!!");
}
}
export和export default的区别(面试题)
1、两者均可用于导出常量、函数、文件、模块;
2、在一个文件中可以多次使用export,但是export default只能用一次;
3、通过export输出的,在import导入时需要使用{},export default不需要;
4、export与export default不可同时使用;
2.18.2.2、引入暴露文件语法
2.18.2.2.1、通用方式
javascript
//1. 通用的导入方式
//引入 m1.js 模块内容
import * as m1 from './js/m1.js'
//引入 m2.js 模块内容
import * as m2 from "./js/m2.js";
//引入 m3.js
import * as m3 from "./js/m3.js";
console.log(m1);
2.18.2.2.2、解构附值
javascript
//2. 解构赋值形式的导入方式
import { school, teach } from "./js/m1.js";
//用别名
import {school as yyzx, findJob} from "./js/m2.js";
import {default as m3} from "./js/m3.js";
2.18.2.2.3、简易形式
javascript
//3. 简便形式的导入方式 针对默认暴露
import m3 from "./js/m3.js";
2.18.2.3、建立入口文件形式
javascript
// app.js 入口文件
//模块引入
import * as m1 from "./m1.js";
import * as m2 from "./m2.js";
import * as m3 from "./m3.js";
console.log(m1);
console.log(m2);
console.log(m3);
javascript
<!--index.html 引入 入口文件 -->
<script src="./js/app.js" type="module"></script>