rest参数
先看ES5中的Arguments,获取实参的方式。
<!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>rest参数</title>
</head>
<body>
<script>
// ES6引入rest参数,用于获取函数的实参,用来代替arguments
// ES5中获取实参的方式
function date(){
console.log(arguments);
}
date('白芷','阿娇');
</script>
</body>
</html>
使用ES6的rest参数,输出是数组的形式。
<!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>rest参数</title>
</head>
<body>
<script>
// ES6引入rest参数,用于获取函数的实参,用来代替arguments
// ES5中获取实参的方式
// function date(){
// console.log(arguments);
// }
// date('白芷','阿娇');
// rest参数
function date(...args) {
// 输出的结果在浏览器中是数组的形式
console.log(args);
}
date('白芷', '阿娇')
// rest参数必须要放到最后,在网页输出中可以看到,a和b输出的是数,args是数组的形式
function cv(a, b, ...args) {
console.log(a);
console.log(b);
console.log(args);
}
cv('1', '2', '3')
</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>扩展运算符</title>
</head>
<body>
<!-- 扩展运算符是个符号,符号的形式是 ... 能把数组转换为逗号分隔的参数序列 -->
<script>
const tf = ['哈哈', '呵呵', '嘎嘎'];
// 声明一个函数
function zhuanhuan() {
console.log(arguments);
}
zhuanhuan(tf)
</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>扩展运算符</title>
</head>
<body>
<!-- 扩展运算符是个符号,符号的形式是 ... 能把数组转换为逗号分隔的参数序列 -->
<script>
const tf = ['哈哈', '呵呵', '嘎嘎'];
// 声明一个函数
function zhuanhuan() {
console.log(arguments);
}
zhuanhuan(...tf);
</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>扩展运算符的应用</title>
</head>
<body>
<div></div>
<div></div>
<div></div>
<script>
// 1.数组的合并
const kuaizi = ['旺旺', '漏喽'];
const fenghuang = ['卡卡', '哦哦'];
// 普通数组合并
// const wudi = kuaizi.concat(fenghuang);
// 打印wudi,在网页输出中可以看到,输出了四个参数
// console.log(wudi);
// 使用扩展运算符数组合并
// 打印wudi,网页输出中可以看到一样的效果
const wudi = [...kuaizi, ...fenghuang]
console.log(wudi);
// 2.数组的克隆
const qq = ['a', 'b', 'c'];
const ww = [...qq];
// 输出的ww和qq的内容一样
console.log(ww);
// 3.将伪数组转换为真正的数组
const divs = document.querySelectorAll('div');
const divarr = [...divs]
console.log(divarr);
</script>
</body>
</html>
Symbol基本使用
<!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>Symbol基本使用</title>
</head>
<body>
<!-- ES6引入了一种新的数据类型 -->
<script>
// 创建symbol,通过一个函数
let s = Symbol();
// 打印一下s以及s的类型,网页后台打印输出的类型是“symbol”
console.log(s, typeof s);
// 第二种创建的方式,还能传入一个字符串
let s2 = Symbol('哈哈');
let s3 = Symbol('哈哈');
// 我们打印输出一下,s2和s3是否一样,实际输出为false
// 可以理解为有两个张三,但是张三的编号是不一样的
console.log(s2 === s3);
// 第三种方式,symbol.for()创建
// symbol.for访问的是全局的symbol表,如果有了就访问对应对象,没有就创建
let s4 = Symbol.for('哈哈');
let s5 = Symbol.for('哈哈')
console.log(s4, typeof s4);
// 这里网页打印输出的是true
console.log(s4 === s5);
// 注意,symbol不能与其他数据运算
// let result = s + 100;
</script>
</body>
</html>
小结下,已有的数据类型:
Symbol使用
symbol创建对象属性
<!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>symbol创建对象属性</title>
</head>
<body>
<script>
// 向对象中添加方法 ,表示其独一无二的特点
let game = {
};
//声明一个方法,都带有symbol属性
let methods = {
up: Symbol(),
down: Symbol()
};
game[methods.up] = function () {
console.log('我可以改变形状');
}
game[methods.down] = function () {
console.log('我可以快速下降');
}
// 这样就给对象game中快速添加了方法,每个方法都不同
// 打印结果输出新加了两个symbol属性
console.log(game);
// 举例,给youxi,这个对象添加独一无二的方法
let youxi = {
name: "狼人杀",
say: Symbol(),
zibao: Symbol()
}
youxi[methods.up] = function () {
console.log('发言');
}
youxi[methods.down] = function () {
console.log('自爆');
}
// 打印结果输出有四个symbol
console.log(youxi);
</script>
</body>
</html>
Symbol内置值
<!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>Symbol内置属性</title>
</head>
<body>
<script>
// 演示Symbol.hasinstance。
// 定义一个类,里边加入了静态方法
class Person {
static [Symbol.hasInstance]() {
console.log('我被用来检测类型了');
}
}
// 定义一个空对象o
let o = {};
// 检验,判断Person是否为空对象o的实例,输出为false
// 因为我们并没有把Person写在o里边,o是空的
console.log(o instanceof Person);
// 演示Symbol.isConcatSpreadabe
//
</script>
</body>
</html>
演示isConcatSpreadabe属性
<!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>Symbol内置属性</title>
</head>
<body>
<script>
// 1.演示Symbol.hasinstance。
// 定义一个类,里边加入了静态方法
class Person {
static [Symbol.hasInstance]() {
console.log('我被用来检测类型了');
}
}
// 定义一个空对象o
let o = {};
// 检验,判断Person是否为空对象o的实例,输出为false
// 因为我们并没有把Person写在o里边,o是空的
console.log(o instanceof Person);
//2. 演示Symbol.isConcatSpreadabe
const arr = [1, 2, 3];
const arr2 = [4, 5, 6];
// 加上这个属性为false后,网页打印出来的是1,2,3,array(3),即没有把数组连接后的arr2展开显示
arr2[Symbol.isConcatSpreadable] = false;
// 做数组合并
console.log(arr.concat(arr2));
</script>
</body>
</html>
迭代器
在js中Iterator接口就是对象里边的一个属性。
下边演示使用for of的循环,
<!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>迭代器</title>
</head>
<body>
<script>
// 声明一个数组
const xiyou = ['唐僧', '八戒']
// 使用for of遍历数组
for (let v of xiyou) {
console.log(v);
}
</script>
</body>
</html>
注意与for in的区别
<!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>迭代器</title>
</head>
<body>
<script>
// 声明一个数组
const xiyou = ['唐僧', '八戒']
// 使用for of遍历数组
for (let v in xiyou) {
console.log(v);
}
</script>
</body>
</html>
打印自定义数组的属性,查看有无iterator属性。
<!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>迭代器</title>
</head>
<body>
<script>
// 声明一个数组
const xiyou = ['唐僧', '八戒']
// 使用for of遍历数组
for (let v of xiyou) {
console.log(v);
}
// 打印下xiyou的属性,看看有没有iterator这个属性
console.log(xiyou);
</script>
</body>
</html>
迭代器应用
先演示错误的应用,浏览器提示说没有这个iterator接口,因为原生就带有iterator接口的数据中,不包含对象,包含Arr数组、String字符串等等。
<!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>自定义遍历数据</title>
</head>
<body>
<script>
// 自定义遍历数据的时候,要想到迭代器
const banji = {
name: "终极一班",
stus: ['xiaoming', 'xiaoning', 'xiaohong', 'xiaotian']
}
// 遍历这个对象
for(let v of banji){
console.log(v);
}
</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>自定义遍历数据</title>
</head>
<body>
<script>
// 自定义遍历数据的时候,要想到迭代器
const banji = {
name: "终极一班",
stus: ['xiaoming', 'xiaoning', 'xiaohong', 'xiaotian'],
// 因为自定义的对象原生属性中没有iterator这个接口,所以自己加上
// 创建一个指针对象
[Symbol.iterator]() {
// 声明一个索引变量
let index = 0;
// 声明一个变量保存当前中括号内的this
_this = this;
return {
// 加上next方法
next: function () {
// 根据索引值返回遍历的值
if (index < _this.stus.length) {
// 返回一个包含value和done属性的对象
const result = { value: _this.stus[index], done: false };
// 下标索引值自增
index++;
return result;
} else {
return { value: undefined, done: true }
}
}
}
}
}
// 遍历这个对象
for (let v of banji) {
console.log(v);
}
</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>生成器</title>
</head>
<body>
<script>
// 生成器其实就是一个特殊的函数
// 解决异步编程,传统方式是使用纯回调函数
function* gen() {
console.log("哈哈");
// yield是相当于函数代码的分隔符,把函数代码切成了几块,三个yield切四块
// 加入后,不像以前一样,该中括号内代码一下就全部执行完毕,现在是分段执行
yield '一直';
console.log(222);
yield '没有';
console.log(333);
yield '耳朵';
console.log(444);
}
let iterator = gen();
console.log(iterator);
// 借助迭代器方法运行gen里边的代码,因为打印gen之后发现,里边有next指针属性
iterator.next();
// 分断执行yield代码,每使用一次iterator.next();,执行一段yield代码
iterator.next();
// 输出333
iterator.next();
// 输出444
iterator.next();
</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>生成器函数参数</title>
</head>
<body>
<script>
function* gen(arg) {
//打印传进来的形参
console.log(arg);
let one=yield 111;
console.log(one);
yield 222;
yield 333;
}
// 获取迭代器对象
// 传入一个形参aaa
let iterator = gen('aaa');
// 打印输出执行第一个yield语句隔离的第一段代码的结果
console.log(iterator.next());
// 打印输出执行第二个yield语句的结果,同时next方法可以传入实参,作为上一个yield的返回结果
console.log(iterator.next('bbb'));
// 打印输出执行第三个yield语句的结果
console.log(iterator.next());
</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>生成器函数实例</title>
</head>
<body>
<script>
// 异步编程 文件操作 网络操作(ajax request) 数据库操作
// 1秒后控制台输出111,2秒后控制台输出222,3秒后控制台输出333
// 使用传统的嵌套来实现,最后出现了回调地狱,指一层一层嵌套,调用
// setTimeout(() => {
// console.log(111);
// setTimeout(() => {
// console.log(222);
// setTimeout(() => {
// console.log(333);
// }, 3000)
// }, 2000)
// }, 1000)
// 使用生成器函数实现,先声明三个函数,实现三个不同任务
function one() {
setTimeout(() => { console.log(111); }, 1000)
}
function two() {
setTimeout(() => { console.log(222); }, 2000)
}
function three() {
setTimeout(() => { console.log(333); }, 3000)
}
function* gen() {
// 总共被分割为4段代码
yield one();
yield two();
yield three();
}
// 然后调用生成器函数
let iterator = gen();
// 调用yield分割后的第一段代码
iterator.next();
// 分割后的第二段代码
iterator.next();
iterator.next();
</script>
</body>
</html>