ES6新增的常用语法(let、const、数据结构、模板字符串、箭头函数、set集合、map集合、rest、iterator、generator、promise、constructor)

1.ES5回顾

严格模式

​ 严格模式 是为了避免JS中出现的混杂模式 其实就是常规模式

​ 比如说 变量不用声明 等一些混杂模式需要处理

​ 在JS中定义严格模式只需要在代码前面设定一个字符串 ‘use strict’

​ 严格模式和普通模式之间的区别

​ 1.严格模式中 变量必须使用变量修饰符进行声明 var let

​ 2、在严格模式中 八进制必须使用0o开头

​ 3、eval函数 拥有独立的作用域

​ 4、严格模式中 this不能指向window 如果指向 返回undefined

​ 5、不允许删除变量

<script>
// age = 18;
// console.log(age);

// 定义严格模式
'use strict';
// 1、严格模式中  变量必须使用变量修饰符进行声明  var  let
// num = 100;
// console.log(num);
// var num = 200;
// console.log(num);
// 测试变量的时候  不能使用name  top变量  因为他是BOM中的属性  
// name = 'zhangsan';
// console.log(name);

// 2、在严格模式中  八进制必须使用0o开头
// 在JS中  默认是八进制  如果说使用0开头  那么就是输出八进制
// 但是在严格模式中  我们如果使用八进制  必须使用0o开头
// console.log(023);
// console.log(0o23); 

// 3、eval函数  拥有独立的作用域
// console.log('2+3');
// console.log(eval('2+3'));
// eval('var num = 200');
// console.log(num);

// 4、this不能指向window
// function fn(){
//     return this;
// }
// console.log(fn());

// 5、不允许删除变量
// var num = 200;
// 删除变量  不使用方法  也不是属性  是一个delete命令
// console.log(delete num);
// console.log(num);

var obj = {
    name : 'Tom',
    age : 18
};

delete obj.age;
console.log(obj);
</script>
JSON

​ JSON 是一个独立于语言和平台的工具 它主要的作用是作为配置文件和传输数据

​ 为什么传输数据使用JSON 因为速度快 体积小 独立与语言 平台 不会造成数据流式 任何语言几乎都支持JSON

​ 使用

​ 序列化 : 将JS中的对象转化为JSON

​ 使用JSON对象中的函数 JSON.Stringify 内置一个参数 参数是对象

​ 反序列化 : 将JSON转化为JS的对象

​ 使用JSON对象中的函数 JSON.parse 内置一个参数 参数是JSON

var obj = {
    name : 'Tom',
    age : 18,
    sex : '男'
};

var arr = [
    {name : 'Tom',age : 18,school : '吉林大学'},
    {name : 'Mary',age : 13,school : '四川大学'},
    {name : 'Tom',age : 3,school : '哈佛大学'},
    {name : 'Jerry',age : 4,school : '麻省理工'},
    {name : 'Jack',age : 25,school : '剑桥大学'},
];

console.log(obj);
// 将对象转化为JSON
var json1 = JSON.stringify(obj);
console.log(json1);
console.log(typeof json1);

var json2 = JSON.stringify(arr);
console.log(json2);
console.log(typeof json2);

// 将JSON转化为对象
var newObj = JSON.parse(json1);
console.log(newObj);
console.log(typeof newObj);

var newArr = JSON.parse(json2)
console.log(newArr);
console.log(typeof newArr);

// 检测数据类型
console.log(Object.prototype.toString.call(newArr));
console.log(Object.prototype.toString.call(newObj));
console.log(Object.prototype.toString.call(json1));

// 手写一个JSON
var json3 = '{"username":"admin","password":"123"}';
console.log(json3);
console.log(typeof json3);
对象的扩展

​ create : 以一个对象为原型创建另一个对象 实质上就是实现了一个对象的继承

​ 内置两个参数 第一个参数是原对象 第二个参数是一个描述 描述是一个对象

​ 对象中内置一个属性 属性是新增的对象属性 属性的值还是一个对象

​ 对象中内置四个属性 四个属性都是修饰对象使用的

​ value :值

​ writable : 是否可写 是否可以修改 默认为fasle

​ enumurable : 是否课枚举 就是遍历 默认为fasle

​ configerable : 是否可删除 默认为fasle

​ 返回值是一个新的对象

/*
create  : 以一个对象为原型创建另一个对象  实质上就是实现了一个对象的继承
    内置两个参数  第一个参数是原对象   第二个参数是一个描述  描述是一个对象
    对象中内置一个属性  属性是新增的对象属性  属性的值还是一个对象
    对象中内置四个属性  四个属性都是修饰对象使用的
        value  :值
        writable  :  是否可写  是否可以修改
        enumurable  :  是否课枚举  就是遍历
        configerable  :  是否可删除
    返回值是一个新的对象
*/

// 定义一个原对象
var obj = {
    name : 'Tom',
    age : 18,
    sex : '男'
};

// 使用create方法  以obj为原型对象基础  创建一个新的对象
var newObj = Object.create(obj,{
    school : {
        value : '吉林大学',
        writable : false,
        configurable : false,
        enumerable : false
    },
    address : {
        value : '吉林长春',
        writable : true,
        configurable : true,
        enumerable : true
    },
});

console.log(newObj);
// console.log(newObj.name);
// 修改属性
newObj.address = '北京市朝阳区';
newObj.school = '北京大学';
console.log(newObj);

// 删除属性
// delete newObj.address;
// delete newObj.school;
// console.log(newObj);

// 遍历属性
for (var key in newObj){
    console.log(key + '===>>>' + newObj[key]);
}

​ defineProperties : 给对象添加一个属性

​ 内置两个参数 第一个参数是原对象 第二个参数是一个描述 描述还是一个对象

​ 对象中内置一个属性 属性是新增的对象属性

​ 属性值还是一个对象 内置两个方法 set get

​ get方法 : 当我们调用新增属性的时候 会被自动触发 调用

​ set方法 : 当我们设置新增属性的时候 会被自动触发 调用

​ set参数可以接受一个参数 参数就是我们设置的属性值

var obj = {
    firstName : '悟空',
    lastName : '孙'
};

Object.defineProperties(obj,{
    fillName : {
        get : function(){
            return this.lastName + this.firstName;
        },
        set : function(name){
            this.lastName = name.slice(0,1);
            this.firstName = name.slice(1);
        }
    }
});

// 当我们使用属性的时候  自动调用get方法
console.log(obj.fillName);

// 当我们修改属性的时候  自动调用set
// set参数可以接受一个参数   参数就是我们设置的属性值
// obj.fillName = '敖广';
obj.fillName = '斯塔夫里阿诺斯';
console.log(obj.fillName);

2、let变量和const常量

let变量

​ let变量是ES新增语法之一 在我们之前的学习中 一直使用var进行声明变量 但是从ES6开始 我们开始使用let进行声明变量

​ 传统的var变量 逐渐的消失了 因为let变量有几点升级

​ let 和 var之间的区别

1.let变量不能重复定义 : 在同一只作用域下 let变量不能重复定义

2.let变量不做变量提升

3.let变量是块作用域 : 块作用域指的是在大括号{}中定义的let变量 在大括号的外部是无法访问的

​ 块级作用域在什么语句中产生 : if while do…while for

​ 4.暂时性死区 : 如果说在块级作用域中 出现了变量提升问题 哪怕在全局作用域中有变量 那么也无法读取 产生暂时性死区

<script>
// let变量不能重新定义
// var num = 100;
// var num = 200;
// console.log(num);

// let num = 200;
// let num = 300;  // Identifier 'num' has already been declared
// console.log(num);


// let 变量不做变量提升
// console.log(num);
// var num = 100;
// let num = 300;  // Cannot access 'num' before initialization


// let变量是块作用域
// {
//     var name = 'Tom';
//     var age = 18;
// }
// console.log(name);
// console.log(age);

// let username = "root";

// {
//     let username = 'admin';
//     let password = '123';
//     console.log(username);
// }

// console.log(username);

// if (true){
//     let user = 'admin';
// }
// console.log(user);


// 暂时性死区
let username = 'admin';

if (true){
    console.log(username);
    let username = 'root';
}
</script>

let变量小案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button>按钮1</button>
    <button>按钮2</button>
    <button>按钮3</button>
    <button>按钮4</button>
    <button>按钮5</button>
    <button>按钮6</button>
    <button>按钮7</button>
    <button>按钮8</button>
</body>
</html>
<script>
let oBtns = document.querySelectorAll('button');
// for (var i = 0;i < oBtns.length; i++){
//     oBtns[i].index = i
//     oBtns[i].onclick = function(){
//         alert(this.index + 1);
//     }
// }
for (let i = 0;i < oBtns.length; i++){
    oBtns[i].onclick = function(){
        alert(i + 1);
    }
}
</script>
const常量

​ 常量 : 是一个一经定义就不再改变的量 不能修改 不能重新赋值或者重新定义 更不能重复定义

​ 所以说 使用的时候 一般情况下都是用在不用修改的量上面

​ 不能修改指的是不能修改其堆栈空间 不是不能修改其内容

​ 常量也是块级作用域 和let变量不同的是 不能修改

​ 要求 :常量在定义的时候必须赋值

​ 常量使用const定义

// let num = 300;
// num = 400;
// console.log(num);

// 常量使用const定义
// const num = 300;
// const num = 400;  // Identifier 'num' has already been declared
// num = 400;  // Assignment to constant variable
// delete num;  // 不能删除
// console.log(num);

// 常量是块级作用域
// if (true){
//     const num = 300;
// }
// console.log(num);  // num is not defined

// 常量不是不能修改  是不能修改其空间内容
// 只是不能修改堆栈空间
const arr = [11,33,55,99];
console.log(arr);

arr.push(88);
console.log(arr);

3、解构赋值

​ 解构赋值就是将对象或者是数组中的元素或者属性都取出来 赋值给一个或者多个变量

​ 在以前我们使用对象中的属性或者是数组中的元素的时候 我们都是按照下标或者是属性的键值一个一个取出来

​ 不能直接将所有的数据取出

​ 在ES6语法中 我们新增的知识点是结构赋值 可以将对象或者是数组中的数据 一次性取出

数组的解构赋值
数组的解构赋值

​ 数组的解构赋值 是使用数组进行解构 也就是说 我们定义多个变量 将数组中的数据取出

​ 那么 我们需要将这些变量定义在一个数组中

​ 然后按照数组的下标顺序 对原数组中的数据进行解构

​ 也就是对抽象的数组中的变量进行一一赋值

数组的完全解构

​ 数组的完全解构就是我们定义的变量和数组中的元素的数量保持一致

​ 将所有的数组元素取出 将所有的变量进行赋值

数组的不完全解构

​ 数组元素的数量大于变量的数量

​ 不会报错 只是不能将数组元素完全取出

​ 变量的数量大于数组元素的数量

​ 也不会报错 但是不能赋值的变量 结果是undefined

默认值解构

​ 为了避免不完全解构中出现undefined 那么我们需要给变量设定默认值

​ 直接在解构赋值之前给变量设定默认值

占位符解构

​ 我可能只是需要数组中的一个元素 没有必要声明太多的变量

​ 那么 我们就可以使用占位符进行解构赋值 在这里 逗号是占位符

<script>
// let arr = [11,33,55,99];
// let one = arr[0];
// let two = arr[1];

// 数组的解构赋值
/*
    数组的解构赋值
    数组的解构赋值  是使用数组进行解构  也就是说  我们定义多个变量  将数组中的数据取出
    那么  我们需要将这些变量定义在一个数组中
    然后按照数组的下标顺序  对原数组中的数据进行解构
    也就是对抽象的数组中的变量进行一一赋值

    数组的完全解构
        数组的完全解构就是我们定义的变量和数组中的元素的数量保持一致
        将所有的数组元素取出  将所有的变量进行赋值
    数组的不完全解构
        数组元素的数量大于变量的数量
            不会报错  只是不能将数组元素完全取出
        变量的数量大于数组元素的数量
            也不会报错  但是不能赋值的变量  结果是undefined
    默认值解构
        为了避免不完全解构中出现undefined  那么我们需要给变量设定默认值
        直接在解构赋值之前给变量设定默认值
    占位符解构
        我可能只是需要数组中的一个元素  没有必要声明太多的变量
        那么  我们就可以使用占位符进行解构赋值  在这里  逗号是占位符

*/

// let a,b,c,d = arr;
// console.log(a);
// console.log(b);
// console.log(c);
// console.log(d);

// 数组的完全解构
// let [a,b,c,d] = arr;
// console.log(a);
// console.log(b);
// console.log(c);
// console.log(d);

// 数组的不完全解构
// let [a,b] = arr;
// console.log(a);
// console.log(b);

// let [a,b,c,d,e] = arr;
// console.log(a);
// console.log(b);
// console.log(c);
// console.log(d);
// console.log(e);
// console.log(arr[4]);

// function fun(a = 0,b = 0,c = 0,d = 0,e = 0){
//     return a+b+c+d+e;
// }
// console.log(fun(2));

// 解构默认值
// let [a,b,c,d,e = 0] = arr;
// console.log(a);
// console.log(b);
// console.log(c);
// console.log(d);
// console.log(e);

// 占位符解构赋值
let arr = [11,33,55,99,66,88,22,44];
let arr = [11,33,55,99,[66,88],22,44];
// let [,,,,num] = arr;
let [,,,,[,num]] = arr;
console.log(num);




</script>
字符串的结构赋值

​ 字符串的解构赋值和数组的一模一样 ,因为字符串也是有下标的 有序的 但是没有键值对

​ 所以说字符串 的解构和数组的完全一致

<script>
// let string = 'benz';
// let [a,b,c,d] = string;
// console.log(a);
// console.log(b);
// console.log(c);
// console.log(d);


// let string = 'benz';
// let [a,b,c,d,e] = string;
// console.log(a);
// console.log(b);
// console.log(c);
// console.log(d);
// console.log(e);

// let string = 'benz';
// let [a,b] = string;
// console.log(a);
// console.log(b);

// let string = 'benz';
// let [a,b,c,d,e = 'hi'] = string;
// console.log(a);
// console.log(b);
// console.log(c);
// console.log(d);
// console.log(e);

let string = 'benz';
let [,,a] = string;
console.log(a);

</script>
对象的结构赋值

​ 对象的解构赋值 对象的结构赋值使用对象

​ 他和数组不同 数组使用的是中括号[] 对象使用的是大括号{} 对象和数组的结构赋值不同

​ 因为对象是无序的 但是对象有键名

​ 所以说对象的解构和数组不同

对象解构赋值和数组解构赋值的区别

对象是按照键名进行解构的 数组是按照下标进行解构的

数组使用的是中括号[] 对象使用的是大括号{}

解构数组的时候 变量的名字是自定义的 解构对象的时候 解构时键名需要保持一直 但是可以不按顺序解构

​ 对象的完全解构

	 按照键名将所有的对象属性全部取出

	对象的不完全解构

​ 对象的属性的数量多于变量 不完全解构

​ 变量的数量多于对象的属性 出现undefined

	默认值解构
<script>
// 定义一个对象
let obj = {
    name : 'Tom',
    age : 18,
    sex : '男'
};

/*
    对象的完全解构
        按照键名将所有的对象属性全部取出
    对象的不完全解构
        对象的属性的数量多于变量  不完全解构
        变量的数量多于对象的属性  出现undefined
    默认值解构
*/

// 对对象进行解构
// let {name : uname,sex : usex,age : uage} = obj;
// console.log(uname);
// console.log(uage);
// console.log(usex);


// 不完全解构
// let {name : uname,sex : usex} = obj;
// console.log(uname);
// console.log(usex);

// let {name : uname,sex : usex,age : uage,school : uschool} = obj;
// console.log(uname);
// console.log(uage);
// console.log(usex);
// console.log(uschool);

// 默认值解构
let {name : uname,sex : usex,age : uage,school : uschool = '吉林大学'} = obj;
console.log(uname);
console.log(uage);
console.log(usex);
console.log(uschool);

</script>
函数参数的结构赋值
<script>
let arr = [11,33,55,99];
let obj = {username : 'admin',password : '123'};

function fun([a,b,c,d] = arr){
    // console.log(arr);
    console.log(a);
    console.log(b);
    console.log(c);
    console.log(d);
}
fun(arr)

function func1({username : user,password : pass}=obj){
    console.log(user);
    console.log(pass);
}
func1();
func1(obj);

// 在解构之前  赋值一个默认对象
function func({username : user,password : pass}={username : 'root',password : 'qwe'}){
    console.log(user);
    console.log(pass);
}
func();
func(obj);
</script>

4、对象属性的简写

对象简写方式

​ 对象的属性简写 指的是 在我们使用对象的时候 很多时候 我们对象的值会是一个标识符

​ 如果说对象属性的值是标识符并且和对象的键名保持一致 也就是相同的名字 那么我们可以省略其一

​ 对象如果说内部有方法 我们可以省略function 直接使用方法名

let username = 'admin123';
let password = '123456';

// 传统对象的编辑方式
// let obj = {
//     username : username,
//     password : password,
//     login : function(){
//         console.log(this.username + '使用' + this.password + '进行登录');
//     }
// };

// ES6中对象的简写方式
let obj = {
    username,
    password,
    login(){
        console.log(this.username + '使用' + this.password + '进行登录111');
    }
}

console.log(obj);
console.log(obj.username);
console.log(obj.password);
obj.login();
对象简写解构赋值

​ 使用对象的简写方式进行解构赋值

// 因为有了对象的简写形式  所以说  我们可以使用这种格式进行对象的解构赋值
let me = {
    name : 'Tom',
    age : 18,
    sex : '男'
};

// let {name:name,age:age,sex:sex} = me;
// let {name,age,sex} = me;
console.log(name);
console.log(age);
console.log(sex);
追加对象属性

​ 如果说你给对象添加属性的时候 我想使用标识符的值作为属性的名字 那么怎么做

​ 如果说 使用这种方式 需要给标识符在对象中添加一个中括号

​ 或者说在追加给对象的时候 我们还是使用中括号

let uname = '姓名';
let uage = '年龄';
let usex = '性别';

// 我现在想使用name  age  sex  这几个标识符的属性值  作为对象的键
let obj = {
    [uname] : 'Tom',
    [uage] : 18,
    usex : '男'
}
console.log(obj);

let user = {
    username : 'admin',
    password : '213'
};
user[uname] = 'Tom';
user[usex] = '男';
user.uage = 18;

console.log(user);

5、模板字符串

​ 模板字符串是ES6新增的字符串定义方式 他可以避免字符串的嵌套和拼接 我们可以直接使用字符串 不再嵌套和拼接

​ 也不再因为引号影响操作 最重要的是 在模板字符串中 还可以识别标识符

​ 模板字符串使用反引号定义 里面可以出现任意字符 如果说出现了标识符 我们使用${标识符}

// 模板字符串
let obj = {
    name : 'Tom',
    age : 18,
    sex : '男',
    say : "人生得意须尽欢"
};

// 定义一个字符串
let {name,age,sex,say} = obj;
let str1 = "我叫" + name + ",今年" + age + "岁,是一个" + sex + "生,昨天我说:'" + say + "'";
console.log(str1);

// 如果说使用模板字符串
let str2 = `我叫${name},今年${age}岁,是一个${sex}生,昨'天"'我"说:'${say}'`;
console.log(str2);

模板字符串的优点

1.不需要做字符串的拼接

2.可以识别标识符 使用${}

模板字符串的缺点

速度相对来说可能比较吗 需要识别字符串中的标识符

// 模板字符串
let obj = {
    name : 'Tom',
    age : 18,
    sex : '男',
    say : "人生得意须尽欢"
};

// 定义一个字符串
let {name,age,sex,say} = obj;
let str1 = "我叫" + name + ",今年" + age + "岁,是一个" + sex + "生,昨天我说:'" + say + "'";
console.log(str1);

// 如果说使用模板字符串
let str2 = `我叫${name},今年${age}岁,是一个${sex}生,昨'天"'我"说:'${say}'`;
console.log(str2);

小案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            padding: 0px;
            margin: 0px;
        }
        #app{
            width: 750px;
            height: 220px;
            margin: 100px auto;
            border: 1px solid;
        }
        #app .big{
            float: left;
        }
        #app .image{
            width: 125px;
            height: 180px;
            margin-top: 10px;
            margin-left: 15px;
        }
        #app .image img{
            width: 100%;
            height: 100%;
        }
        #app .intro{
            text-align: center;
            width: 125px;
            margin-left: 15px;
            line-height: 30px;
        }
        #app .intro span{
            color: orange;
        }
    </style>
</head>
<body>
    <div id="app">

    </div>
</body>
</html>
<script>
let arr = [
    {title : "一秒钟",score : 7.8,src : "https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2628373757.jpg"},
    {title : "2020去死",score : 7.3,src : "https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2628834126.jpg"},
    {title : "夺冠",score : 7.3,src : "https://img2.doubanio.com/view/photo/s_ratio_poster/public/p2620083313.jpg"},
    {title : "信条",score : 7.7,src : "https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2618403186.jpg"},
    {title : "菊石",score : 7.1,src : "https://img2.doubanio.com/view/photo/s_ratio_poster/public/p2618286922.jpg"},
];

let str = arr.map(function(value){
    let {title,score,src} = value;
    return `<div class="big"><div>
            <div class="image">
                <img src="${src}" >
            </div>
            <div class="intro">
                ${title}&nbsp;&nbsp;<span>${score}</span>
            </div>
        </div></div>`;
}).join('');
app.innerHTML = str;
</script>

6、箭头函数

箭头函数是ES6中对函数的重新的抽象 我们在ES6中使用函数的时候 不需要那么麻烦 不需要使用function

我们定义箭头函数的时候 需要直接使用()=>{} 这个就是箭头函数

箭头函数的特性

箭头和常规函数的区别 也是箭头函数的特性

1.箭头函数只能定义匿名函数

2.箭头函数没有原型对象 不能用作构造函数

3.特殊省略 当箭头函数只有一个参数的时候 可以省略小括号 形参列表括号

4.特殊省略 当箭头函数函数体只有一句话的时候 那么可以省略大括号 如果说这句话还是返回值 省略了大括号后必须省略return

5.如果说箭头函数省略了大括号 那么返回值不能是对象 如果是对象那个 必须使用小括号包裹

6.箭头函数不能使用arguments super new等关键字

7.箭头函数没有自己的this 它使用父级的this

箭头函数的写法
箭头函数直接使用小括号  然后是箭头   大括号    省略函数名和function
/*
常规函数的结构
function [函数名]([形参列表]){
    函数体
    [return  返回值]
}

[函数名]([与形参列表保持一致])

箭头函数结构
()=>{

}

只有=>是必选

*/

let fun = ()=>{
    console.log('今天是阴天');
    console.log('今天没下雨');
    console.log('今天很冷');
}

fun();
console.log(typeof fun);
console.log(Object.prototype.toString.call(fun));
箭头函数特性检测

​ 箭头函数不能做构造函数

// 箭头函数没有原型对象  不能定义构造函数
function Car(name,color,price) {
    this.name = name;
    this.color = color;
    this.price = price;
}

// 实例化构造方法
let c = new Car('benz','黑色',860000);
console.log(c);


let Cat = (name,color)=>{
    this.name = name;
    this.color = color;
}

let a = new Cat('小白','黑色');
console.log(a);  // 报错 : Cat is not a constructor

​ 特殊省略 省略小括号

let fun = m=>{
    console.log(m + 100);
}

fun(30);

// let func = =>{
    // 直接报错
// }

// let func = m,n=>{
//     // 直接报错
// }

​ 特殊省略 省略大括号和return

// 省略大括号
// let fun = ()=>console.log('你好  中国');
// fun();

// 如果说省略大括号  但是这句话还是返回值  那么必须省略return
// let fun = ()=>{
//     return 123;
// }
// console.log(fun());

// let fun = ()=>return 123;  //直接报错

let fun = ()=>'你好  成都';
console.log(fun());

​ 省略大括号 返回值是对象

​ 因为 省略函数体的大括号 但是返回对象的时候 有省略了return 所以说函数和对象分不清大括号是谁的

​ 解决方案 用小括号将对象包裹

// 当省略大括号的时候  返回值是对象
let fun = ()=>({name:'Tom',age:18});

​ 箭头函数 不能使用arguments super new等关键字

// 箭头函数不能使用arguments
// function name() {
//     console.log(arguments.length);
//     console.log(arguments);
// }

// name(1,2,3,4,5,6);

let name = ()=>{
    console.log(arguments.length);
    console.log(arguments);
}

name(1,2,3,4,5,6);  // 报错  :  arguments is not defined

​ 箭头函数没有自己的this

7. rest参数

​ rest参数是我们在ES6中新增的语法格式 他可以解析任何数据类型 比如说数组 对象 以及我们后面学的集合

​ 在我们使用rest参数的时候 我们需要在前面加上… 虽然知识点的名字叫做rest 但是名字我们自定义

​ 我们使用rest解开数组或者对象

let arr = [11,22,33,55,99];

console.log(arr);
// 使用...arr   将这三个点放在数组的前面   等于把数组中的元素取出
console.log(...arr);

// 如果说取出对象  直接取出的时候  会产生报错
let obj = {
    name : 'Tom',
    age : 18
};

// console.log(...obj);

// 可以使用...拷贝一个对象   那么是可以取出的
let newObj = {
    ...obj
};

console.log(newObj);

// 数组去重
let arr1 = [1,7,3,0,1,0,7,9,2,0,1];
let set = new Set(arr1);
let newArr1 = [...set];
console.log(newArr1);

​ 当然 rest也可以作为剩余参数使用 也就是我们所说的传递不定参数 和arguments类似

​ 因为在我们ES6中 我们大多数时候使用的是箭头函数 但是箭头函数不能使用arguments

​ 如果说 我们需要传递不定参数 那么我们是无法使用的

​ 那么这会 我们可以使用剩余参数

​ 剩余参数 使用的时候 需要在形参列表中有所体现 参数的名字自定义 但是参数前面要加上…

// 求和函数  一般情况下是N个加数

// let sum = (...value)=>{
//     // console.log(value);
//     let total = 0;
//     value.forEach(element=>total += element);
//     console.log(total);
// }
// sum(1,2,3,4,5,7);

// 传递普通参数
let sum = (a,c,...value)=>{
    console.log(value);
    let total = 0;
    value.forEach(element=>total += element);
    console.log(total);
}
sum(1,2,3,4,5,6,7);

// 错误的写法   如果说传递普通参数  那么剩余参数一定要在最后
// let sum = (...value,a,c)=>{
//     console.log(value);
//     let total = 0;
//     value.forEach(element=>total += element);
//     console.log(total);
// }
// sum(1,2,3,4,5,6,7);

rest参数和arguments参数的区别

1.arguments不能在箭头函数中使用 但是rest可以在箭头函数中使用

2.arguments传参的时候 我们不能在形参列表中传递参数 但是rest传参 我们必须在形参列表中使用 并且是…参数名

3.rest参数可以和常规参数一起进行传递 arguments不能 但是 如果说传递常规参数 那么rest参数必须放在最后

8. Symbol数据类型

定义

​ Symbol他是ES6新增的一种数据类型 它主要的作用是保证数据的唯一性

​ 比如说对象的属性的名字或者是方法的名字 可能会出现一些冲突 那么我们可以使用Symbol进行解决

​ 同时定义的两个Symbol 他们绝对不会相等

​ 他不是对象 也不是函数 只是一种数据类型 但是使用的时候 还是需要调用

// 使用Symbol
let sym1 = Symbol();

// console.log(sym1);
// console.log(typeof sym1);
// console.log(sym1 == sym1);  // true

let sym2 = Symbol();
// 两个Symbol绝对不相等
console.log(sym1 == sym2);  // false

​ 但是 我们在使用的时候 基本上使用的比较麻烦 因为我们无法确定Symbol()是什么 如果说这个Symbol作为对象的键

​ 我们都无法确认对象的键具体的代表是什么

​ 这中情况下 我们可以想Symbol内部传递一个参数 参数作为Symbol的标识

​ 但是注意 即使传递的参数相同 那么两个Symbol还是不会相等

let name = Symbol('姓名');
let user = Symbol('姓名');
let age = Symbol('年龄');

console.log(name);
console.log(age);
console.log(user);
console.log(user == name);  // false

​ 注意 Symbol数据类型不能和其他任何数据类型进行运算

console.log(age + "abc");
console.log(age + 123);
console.log(age + 12.3);
console.log(age + true);
console.log(age + undefined);
console.log(age + null);
使用

​ 有三种方式可以使用

​ 1.直接在对象中使用

​ 2.可以追加对象属性

​ 3.使用defineProperty方法进行添加属性

<script>
let name = Symbol('姓名');
let age = Symbol('年龄');
let sex = Symbol('性别');
let school = Symbol('学校');
let like = Symbol('爱好');
let address = Symbol('地址');
let birth = Symbol('生日');

// 第一种方式  直接添加
let obj = {
    [name] : 'Tom',
    [age] : 18,
    [sex] : '男',
    [school] : '吉林大学',
    [like] : ['吃','喝','旅游','女','学习','开车']
}
console.log(obj);
console.log(obj[age]);
console.log(obj[birth]);

// 第二种方式   向对象中追加属性
obj[address] = '吉林长春';

// 第三种方式  使用defineProperty方法进行追加属性
// 内置三个参数  第一个参数是原对象
// 第二个参数是Symbol
// 第三个参数是描述  描述还是一个对象  描述中有一个属性  属性是名value  值是新增属性值
Object.defineProperty(obj,birth,{
    value : '2002-07-18'
})

console.log(obj);
</script>

9. set集合

​ set是ES6中新增的数据结构 他是一个无序的 不重复的集合 该结构类似于数组

​ 他是主要用来存储一些不重复的数据 或者作为数组去重使用

​ 使用set集合必须先进行实例化 new 可以内置一个参数 也可以不传参数 参数是一个数组

​ 内置方法

​ add : 添加一个集合元素

​ size属性 : 查看集合元素的数量 和数组的length一致

​ delete : 删除一个集合元素

​ has : 查看元素是否存在在这个集合中

​ clear : 清空集合

<script>
let arr = [1,7,3,0,1,0,7,9,2,0,1];

// 实例化一个set集合
let set = new Set(arr);
// let set1 = new Set();
console.log(set);
// console.log(set1);

// add  :  添加一个集合元素
set.add(99);
console.log(set);

// delete  :  删除一个元素
set.delete(99);
console.log(set);

// has  :  查看一个元素是否存在在集合中
console.log(set.has(1));
console.log(set.has(5));
console.log(set.has(9));
console.log(set.has(99));

// size属性  :  查看集合中的元素的数量
console.log(set.size);

// clear  :  清空集合
set.clear();
console.log(set);
</script>

数组的去重

<script>
let arr = [1,7,3,0,1,0,7,9,2,0,1];

// 首先去重数组  先定义一个set集合  将数组中的元素放到set集合中
// set集合会自动将数组的元素进行去重
let set = new Set(arr);
// console.log(set);

// 然后将set中的元素都取出来
// 注意  set不能使用for循环  或者是for...in进行遍历   需要使用for...of
// 但是我们可以使用剩余参数   解开集合   存储到新的数组中
let newArr = [...set];

console.log(newArr);
</script>

10. map集合

​ map也是ES6中新增的数据结构 他也是一个无序的 不重复的集合 但是和set不同的是 set结构类似于数组,

​ map的结构类似于对象 每一个元素是由键值对组成的

​ 在使用的时候 也是和set一样 需要实例化 new Map(参数) 内置一个参数

​ 参数是可选参数 如果说传递参数 那么参数是一个二维数组 每一个子数组内置两个元素 分别作为键值

​ 内置方法

​ set : 添加一个map元素 内置两个参数 第一个参数是键 第二个参数是值

​ delete : 删除一个map元素

​ size属性 : 查看map中的元素数量

​ has : 查看元素是否存在map集合中

​ get : 获取一个map元素

​ clear : 清空map集合

<script>
let arr = [
    ['name','Tom'],
    ['age',18],
    ['sex','男'],
    ['address','吉林长春']
];

// 创建一个map  实例化
let map = new Map(arr);
console.log(map);

// set添加一个元素
map.set('birth','2002-7-18');
console.log(map);

// delete删除一个元素
map.delete('birth');
console.log(map);

// size 查看元素的具体数量
console.log(map.size);

// has  查看元素是否存在在map集合中
console.log(map.has('birth'));
console.log(map.has('name'));

// get  获取一个map集合元素
console.log(map.get('name'));
console.log(map.get('age'));
console.log(map.get('birth'));

// clear  清空集合
map.clear();
console.log(map);
</script>

11. iterator迭代器

简介 : iterator 是一种接口机制 为不同的数据结构提供统一的访问机制

作用

​ 为不同的数据结构提供统一的访问机制

​ 使数据结构成员能够按照某种次序排序 一一迭代出来

​ ES6提供了一个新的遍历办法 for of Iterator主要是提供for of使用

原理

​ 创造一个指针 指向数据结构的起始位置

​ 第一次调用next() 指针自动指向数据结构的第一个成员

​ 接下来不断的调用next() 指针一直往后移动 直到指向最后一个成员

​ 每次调用next的时候 返回的值包括一个value done

​ 如果说 指向数据 返回为真 {value : ‘值’, done : false}

​ 如果说 指向最后了 没有值了 那么返回 {value : undefined , done : true}

​ 原生具备iterator接口的数据(可以用for of遍历)

<script>
let arr = ['贾思勰','左丘明','司马光','司马迁','班超','辛弃疾','郦道元'];

/*
    使用iterator接口机制迭代这个数组
        首先  我们创建数组指针  指向数组的起始位置
        每一次使用next方法进行调用  迭代数据
        每一次next之后  那么数组指针下移   指向下一个元素
        如果元素存在  有值  返回对象   {value  : '值',  done  :  false}
        如果说指针移动到最后   那么没有值了  返回对象  {value  :  undefined , done : true}

    首先  我们自定义一个函数  封装一个函数   主要是迭代数组使用

*/

function myIterator(object){
    // 创建数组指针   指向数组中的第0个元素的位置  起始位置
    let index = 0;
    return {
        next : function(){
            if (object.length > index){
                return {value:object[index++],done:false};
            }else{
                return {value:undefined,done:true};
            }
        }
    }
}

let iter = myIterator(arr);
console.log(iter.next());  //{value  : '贾思勰',  done  :  false}
console.log(iter.next());  //{value  : '左丘明',  done  :  false}
console.log(iter.next());  //{value  : '司马光',  done  :  false}
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());

let str = 'abcd';
let striter = myIterator(str);
console.log(striter.next());
console.log(striter.next());
console.log(striter.next());
console.log(striter.next());
console.log(striter.next());
</script>

​ iterator迭代的数据结构

​ 其实在iterator中 我们是存在语法糖的 使用字符串 数组 set集合 map集合 中的[Symbol.iterator]()方法进行迭代

​ 注意 iterator不能迭代对象 iterator的语法糖也不能迭代对象

<script>
let arr = ['贾思勰','左丘明','司马光','司马迁','班超','辛弃疾','郦道元'];
// 使用iterator迭代数组
// 首先调用[Symbol.iterator]方法
let arrIter = arr[Symbol.iterator]();
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log('*'.repeat(50));


// 使用iterator迭代字符串
let str = 'abc';
let strIter = str[Symbol.iterator]();
console.log(strIter.next());
console.log(strIter.next());
console.log(strIter.next());
console.log(strIter.next());
console.log('*'.repeat(50));


// 使用iterator迭代set集合
let set = new Set(arr);
let setIter = set[Symbol.iterator]();
console.log(setIter.next());
console.log(setIter.next());
console.log(setIter.next());
console.log(setIter.next());
console.log(setIter.next());
console.log(setIter.next());
console.log(setIter.next());
console.log(setIter.next());
console.log('*'.repeat(50));


// 使用iterator迭代map集合
let map = new Map([['name','Tom'],['age',18]]);
let mapIter = map[Symbol.iterator]();
console.log(mapIter.next());
console.log(mapIter.next());
console.log(mapIter.next());


// 不能使用iterator迭代对象
let obj = {
    name : 'Mary',
    age : 13
};

let objIter = obj[Symbol.iterator]();
</script>

​ iterator的语法糖其实是for…of语句

​ for…of 可以迭代任何可迭代的数据类型 但是就是不能迭代对象

<script>
let arr = ['贾思勰','左丘明','司马光','司马迁','班超','辛弃疾','郦道元'];
// 使用for  of迭代数组
// for(let value of arr){
//     console.log(value);
// }

let str = 'abc';
// 使用for...of迭代字符串
// for(let value of str){
//     console.log(value);
// }

let set = new Set(arr);
// 使用for...of迭代set集合
// for(let value of set){
//     console.log(value);
// }

let map = new Map([['name','Tom'],['age',18]]);
// 使用for...of迭代map集合
for(let value of map){
    console.log(value);
}


// 报错  : 所有的数据解构使用for...of  都可以迭代  但是  for...of不能迭代对象
// let obj = {
//     name : 'Mary',
//     age : 13
// };
// for(let value of obj){
//     console.log(value);
// }
</script>

使用iterator迭代对象

<script>
let obj = {
    name : 'Tom',
    age : 18,
    sex : '男'
};

// iterator迭代对象
obj[Symbol.iterator] = function(){
    // 定义数组指针
    let index = 0;
    // 将对象中所有的键取出来组成一个数组
    let keys = Object.keys(this);
    return {
        next : ()=>{
            // 判断数组中的长度是否大于数组指针
            if (keys.length > index){
                return {value : this[keys[index++]],done : false}
            }else{
                return {value : undefined,done : true}
            }
        }
    }
}

let iter = obj[Symbol.iterator]();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
</script>

for…of和for…in和foreach之间的区别

for…of是iterator的语法糖 他能够遍历出iterator所有可迭代的数据类型和数据结构 set map 字符串 数组 不能迭代对象

foreach 只是遍历数组使用 不能用作其他 也不能迭代对象

for…in 是唯一一个可以迭代对象的一种语法结构 当然 也可以迭代数组 字符串

12. generator生成器

简介

​ ES6提供的解决异步编程的方案之一

​ Generator函数是一个状态机, 可控制函数执行过程

​ 可暂停函数(惰性求值), 内部yield可暂停,外部调用next方法可启动

​ 每次返回的是yield后的表达式结果

使用

​ 定义generator需要在function后面加上*

​ 调用函数不会打印任何函数数据,而是会返回一个指针对象

​ 调用指针对象中的next方法,来执行generator函数中的内容

​ 返回结果和iteraator相似

使用

<script>
// generator函数  function后面需要加上一个*  证明是generator
function* myGenerator(){
    yield "这是第一次";
    yield "这是第二次";
    yield "这是第三次";
    yield "这是第四次";
    yield "这是第五次";
    return 'GAMEOVER';
}

let go = myGenerator();
console.log(go.next());
console.log(go.next());
console.log(go.next());
console.log(go.next());
console.log(go.next());
console.log(go.next());
console.log(go.next());


</script>

小案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            padding: 0px;
            margin: 0px;
        }
        #app{
            width: 1200px;
            margin: 0 auto;
            /* border: 1px solid; */
        }
        #app div{
            width: 1200px;
            height: 44px;
            line-height: 44px;
            text-align: center;
            font-size: 20px;
            font-weight: 800;
            margin: 5px 0px;
            border: 1px solid;
        }
        #btn{
            width: 800px;
            height: 35px;
            font-size: 18px;
            display: block;
            margin: 20px auto;
            border: none;
            outline: none;
        }
    </style>
</head>
<body>
    <div id="app">
        <div>显示1——20条数据</div>
    </div>
    <button id="btn">点击加载更多</button>
</body>
</html>
<script>
function* getData(){
    yield "显示21——40条数据";
    yield "显示41——60条数据";
    yield "显示61——80条数据";
    yield "显示81——100条数据";
    yield "显示101——120条数据";
    yield "显示121——140条数据";
    yield "显示141——160条数据";
    yield "显示161——180条数据";
    yield "显示181——200条数据";
    yield "显示201——220条数据";
}

let go = getData();

btn.onclick = function(){
    let div = document.createElement('div');
    let content = go.next().value;
    if (content == undefined){
        btn.style.display = 'none';
    }else{
        div.innerHTML = content;
        app.appendChild(div);
    }
}

</script>

13. promise

概念

​ Promise 是异步编程的一种解决方案,比传统的回调函数和事件更合理、更强大

​ ES6的Promise是一个构造函数, 用来生成Promise实例, Promise实例是异步操作管理者

​ Promise代表了未来某个将要发生的事件(通常是一个异步操作) 有了Promise对象

​ 可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数(回调地狱)

​ Promise本身还是在使用回调函数(只不过比回调函数多了一种状态管理)

使用

​ 创建promise对象,实例化Promise

​ 参数是回调函数,内置两个参数,resolve和reject

​ promise三个状态

​ 初始化状态 pending

​ 成功状态 fullfilled

​ 失败状态 rejected

调用

​ then : 触发resolve方法执行then

​ catch : 触发reject方法执行catch

<script>
/*
    编辑一个Promise
    Promise是一个构造函数   需要实例化才能使用  首先实例化Promise
    内置一个参数  参数是回调函数
        回调内置两个参数
            第一个参数是成功状态  它本身是一个函数
            第二个参数是失败状态  它本身也是一个函数
    promise有一个返回值  返回值是一个promise对象

    在promise内部  我们可以编辑三种状态
        1.初始化状态
        2.成功状态
        3.失败状态
*/

let promise = new Promise((resolve,reject)=>{
    // 定义一个初始值
    let num = 9;
    // 判定初始化状态
    if (num > 99){
        // 成功的话  我们可以调用成功状态   也就是resolve
        // resolve本身是一个函数
        // console.log(typeof resolve);
        resolve('牵手了  成功');
    }else{
        // 失败的话  我们可以调用失败状态  reject  他也是一个函数
        // console.log(typeof reject);
        reject('分手了');
    }
});

// 我们定义完的promise对象和没写一样  和定义的函数一样  没有调用
// 比如说成功状态的函数和是失败状态的函数也没有定义
// 如果说  我们触发promise   那么我们使用promise对象中的then方法进行触发
// then方法中内置一个或者两个参数  第一个参数是成功状态的函数
// 第二个参数是失败状态的函数  可选
promise.then((data)=>{
    console.log(data);
},(error)=>{
    console.log(error);
})
</script>
捕获异常

​ 在使用then的时候是无法捕获异常的

​ 但是在catch中可以捕获异常

​ try : 可能出现异常的代码

​ catch : 如果try出现错误,代码执行catch

​ finally : 不管会不会发生异常,都会执行finally中的代码

<script>
/*
    异常处理
    主要分为三个关键字  分别是try  catch   finally
    try  :  这个执行体中  存放着可能出错的代码
        如果内部代码没有报错行为  那么直接执行  但是如果说代码报错了  那么执行catch里面的代码
    catch  :  准备一些代码  如果说try中的代码出错  我们去处理try中的代码
    finally  :  无论代码报错与否  那么都执行  比较鸡肋
*/

let num = 100;

try{
    console.log(num);
    // console.log('代码没出错的时候执行的');
}catch{
    let num = 100;
    console.log(num);
    // console.log('try里面面有问题了  你想起我来了');
}finally{
    console.log('怎么做我都执行');
}
</script>
链式操作

​ then方法的第一个参数,成功时的回调函数,分两种情况

​ 返回了一个普通的数据(非promise),这个值会作为参数传递给下一个then的成功回调

​ 返回了一个promise,下一个then的执行,取决于这个promise状态的改变

// 捕获异常  详见17.html
// 使我们讲解异常处理  主要是对peomise进行链式操作
// 链式操作
let promise = new Promise((resolve,reject)=>{
    let num = 9;
    if (num > 99){
        resolve('牵手了  成功');
    }else{
        reject('分手了');
    }
});

// 当我们触发promise的时候  使用then方法
// 但是then方法中  我们一般情况下  只传递一个参数  参数是成功状态
// 我们then方法的返回值还是一个promise
// console.log(promise);
// 我们失败状态一般使用catch来处理  这是异常处理
promise.then((data)=>{
    console.log(data);
}).catch((error)=>{
    console.log(error);
})
如何使用promise处理回调地狱
<script>
let promise = new Promise((resolve,reject)=>{
    resolve('京东的工艺');
})

// 我们使用promise对象then完之后  返回值依旧是promise
// 我们可以继续使用then进行触发
// 此时  新的返回值promise中的resolve状态(成功状态)就是刚刚的返回值
// 也就是说  我们触发时候的返回值  作为新的promise的成功状态   resolve状态
promise.then((data)=>{
    console.log(data);
    return data + '里面的打火机';
}).then(data=>{
    console.log(data);
    return data + "里面的zippo";
}).then(data=>{
    console.log(data);
    return data + "里面的黑色的";
}).then(data=>{
    console.log(data);
    return data + "青春靓丽";
}).then(data=>{
    console.log(data + "的打火机");
})
</script>
面试题

谈一谈你对promise的理解?

答案: Promise用来解决异步回调问题,由于js是单线程的,很多异步操作都是依靠回调方法实现的,这种做法在逻辑比较复杂的回调嵌套

中会相当复杂;也叫做回调地狱;promise用来将这种繁杂的做法简化,让程序更具备可读性,可维护性;promise内部有三种状态,

pedding,fulfilled,rejected;pedding表示程序正在执行但未得到结果,即异步操作没有执行完毕,fulfilled表示程序执行完毕,且执

行成功,rejected表示执行完毕但失败;这里的成功和失败都是逻辑意义上的;并非是要报错。其实,promise和回调函数一样,都是要

解决数据的传递和消息发送问题,promise中的then一般对应成功后的数据处理,catch一般对应失败后的数据处理。

promise中的all方法

​ promise中的all方法 不是我们所说的使用promise对象定义的方法 他是使用Promise构造方法定义的方法

​ 他是一个可以执行多个Promise的一种方式 all方法 执行全部的promise

​ Promise.all() 方法 内置一个参数 参数是一个数组 数组中的每一个元素 都是Promise

​ 他们都会一起执行

let p1 = new Promise((resolve,reject)=>{
    console.log(1111);
    resolve('这是第一个Promise');
})

let p2 = new Promise((resolve,reject)=>{
    console.log(2222);
    resolve('这是第二个Promise');
})

let p3 = new Promise((resolve,reject)=>{
    console.log(3333);
    resolve('这是第三个Promise');
})

let p = Promise.all([p1,p2,p3]);
p.then(data=>console.log(data));
promise中的race方法

​ race方法和all方法是一样的 都不是对象方法 都是Promise直接调用的方法 内置也是一个参数 参数还是数组

​ 但是不同的是 race方法不是将所有的promise都执行 而是只执行最快的那个Promise

<script>
let p1 = new Promise((resolve,reject)=>{
    setTimeout(() => {
        // console.log('这是三秒的promise');
        resolve('这是三秒的promise');
    }, 3000);
})

let p2 = new Promise((resolve,reject)=>{
    setTimeout(() => {
        // console.log('这是一秒的promise');
        resolve('这是一秒的promise');
    }, 1000);
})

let p3 = new Promise((resolve,reject)=>{
    setTimeout(() => {
        // console.log('这是两秒的promise');
        resolve('这是两秒的promise');
    }, 2000);
})


// race只是执行最快那个promise
let p = Promise.race([p1,p2,p3]);
p.then(d=>console.log(d));
</script>
promise配合ajax

​ 小案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>ajax和promise</h1>
</body>
</html>
<script src="./jquery.js"></script>
<script>
let promise = new Promise((resolve,reject)=>{
    setTimeout(() => {
        $.ajax({
            url : './index.php',
            type : 'get',
            data : {user : 'Tom'},
            success : (response)=>{
                resolve(response);
            },
            error : (err)=>{
                reject(err);
            }
        })
    }, 200);
})

promise.then(data=>{
    console.log(data);
})

let promise1 = new Promise((resolve,reject)=>{
    $.ajax({
        url : './indexx.php',
        type : 'get',
        success : (response)=>{
            resolve(response);
        },
        error : (err)=>{
            reject(err);
        }
    })
})

promise1.then(data=>{
    console.log(data);
})

</script>

​ 处理异步问题

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>ajax和promise</h1>
</body>
</html>
<script src="./jquery.js"></script>
<script>
let promise = new Promise((resolve,reject)=>{
    setTimeout(() => {
        $.ajax({
            url : './index.php',
            type : 'get',
            data : {user : 'Tom'},
            success : (response)=>{
                resolve(response);
            },
            error : (err)=>{
                reject(err);
            }
        })
    }, 200);
})

promise.then(data=>{
    console.log(data);
    return $.ajax({
        url : './indexx.php',
        type : 'get',
        success : (response)=>{
            return data + response
        },
        error : (err)=>{
            reject(err);
        }
    })
}).then(data=>{
    console.log(data);
})

</script>

14. async…await

​ async…await是promise和generator的语法糖 他是真正意义上解决异步问题的一种方式

​ promise解决异步问题 但是不能从我们promise中取出数据 而async…await是可以做到的

​ 他和generator是一样的 控制函数的执行过程 但是generator是手动的 async是自动的

​ 因为generator需要手动的调用next执行 但是async不需要在外部手动调用

​ async是修饰函数 这个函数的返回值就是一个promise对象

​ async函数中可以有await 他的作用和yield比较相似 程序碰到await会陷入阻塞状态 阻塞到将await后面的表达式执行完毕

​ 执行完毕之后再向下执行 await只存在在async修饰的函数中

​ async函数中的await可以直接获取promise中的resolve或者是reject状态 并且是异常处理之后的状态

​ 也就是说 他可以直接获取出promise的数据

​ async的主要作用

​ 1.async的返回值是一个promise状态

​ 2.async中的await获取promise中的状态 并且是异常处理之后的状态

​ 3.可以将异步的代码转变成同步的代码 将异步的程序以同步的流程表达出来

// 使用async函数  他的返回值是promise
// async function fun(){

// }
// // 只要是使用async修饰的函数的返回值  那么返回值就是promise
// console.log(fun());


// async中的await可以直接获取promise的状态
function to(){
    return new Promise((resolve,reject)=>{
        resolve('这是函数的resolve装填');
    })
}

// let a = to().then(data=>console.log(data))
// console.log(a);

async function test(){
    let a = await to();
    console.log(a);
}
test();

小案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>async...await</h1>
</body>
</html>
<script src="./jquery.js"></script>
<script>
function p1(){
    return new Promise((resolve,reject)=>{
        setTimeout(() => {
            $.ajax({
                url : './index.php',
                type : 'get',
                data : {user : 'Tom'},
                success : (response)=>{
                    resolve(response);
                },
                error : (err)=>{
                    reject(err);
                }
            })
        }, 200);
    })
}

function p2(){
    return new Promise((resolve,reject)=>{
        $.ajax({
            url : './indexx.php',
            type : 'get',
            success : (response)=>{
                resolve(response);
            },
            error : (err)=>{
                reject(err);
            }
        })
    })
}

// p1().then(d=>console.log(d));
// p2().then(d=>console.log(d));

async function test(){
    let v1 = await p1();
    console.log(v1);
    let v2 = await p2();
    console.log(v2);
}
test()

</script>

15.面向对象和面向过程的区别

​ 面向对象指的是将一些可能用到的东西 或者说使用起来比较繁琐的内容 将其封装 使用的时候直接调用

​ 面向过程 在使用的时候定义 如果需要再次使用 那么再次定义

​ 面向对象其实实现的就是封装

面向对象的概念

​ 面向对象的三大特性 封装 继承 多态

​ 多态 : 同一操作 针对不同的对象 会产生不同的执行结果 这就是多态

​ 面向对象的优势:

​ 使用方便 方便项目维护

​ 避免代码冗余

类和对象的关系

​ 类 : 类是泛指的一类事务 抽象

​ 对象 : 对象指的是指定的某件事务 具体

​ 类是对象的抽象 对象是类的具体

​ 类是对象的模板 对象是类的铸件

类的成员

​ 我们在使用对象的时候 这个对象一定是在类中产出的

​ 所以说 我们在使用对象之前 一定先定义一个类

​ 使用class关键字 后面直接跟上类名 类名的命名方式使用帕斯卡命名法

​ 类中存在的成员:

​ 成员属性 : 和变量类似 但是有区别 成员属性在类中是全局的 变量不是 参数也不是

​ 属性指的是对一个事务的描述 一般是名词或者是形容词

​ 成员方法 : 和函数类似 但是有区别 成员方法在类中是全局的

​ 方法指的是一种行为 一般是动词

定义和实例化一个类

​ 定义使用class定义 实例化的时候 使用new进行实例化

​ new后面加上 类名 实参列表

<script>
// 定义一个类
class Person{
    // 定义类中的成员
    name = 'Tom';
    age = 18;

    // 定义类中的方法
    say(pass){
        var user = 'amdin';
        this.pass = pass;
        console.log(this.name + '在说话');
    }
    eat(){
        // console.log(user);
        console.log(this.pass);
        this.say();
        console.log(this.name + '在吃饭');
    }
}

let p = new Person();
console.log(p.name);
console.log(p.age);
p.say('123')
p.eat()
</script>
构造器

​ 构造器 其实是面向对象中的一个特殊的方法 为什么特殊 因为他不需要你手动调用 只要是进行了实例化 那么就会自动调用

​ 构造器在你实例化的时候会被自动调用的

// 构造器
class Dog{
    constructor(){
        console.log('构造器在实例化的时候已经被调用了');
    }
}

new Dog();

​ 构造器的作用

​ 主要用来初始化数据 可以接受参数

​ 那么什么时候向构造器中传参 因为constructor不需要我们手动调用 只需要自动调用

​ 那么 我们使用这个构造器的时候 什么时候传参

​ 实例化的时候有实参 但是类名没有形参

​ 构造器有形参 但是不需要调用 没有实参

​ 他们两个一起执行 都是在实例化的同时执行 所以说 我们可以在实例化的时候传递参数

<script>
// 构造器
// class Dog{
//     constructor(){
//         console.log('构造器在实例化的时候已经被调用了');
//     }
// }
// new Dog();

// class Dog{
//     constructor(name,color,age){
//         console.log(name,color,age);
//     }
// }
// new Dog('大黄','黑色的',3);

class Dog{
    constructor(name,color,age){
        this.name = name;
        this.age = age;
        this.color = color;
    }

    sound(){
        console.log(this.food);
        console.log(`${this.name}每天晚上喵喵叫`);
    }

    eat(food){
        this.food = food;
        console.log(`${this.name}今年${this.age}岁,每天吃的很多${this.food}`);
    }
}

let wd = new Dog('小黑','白色的',3);

wd.eat('狗粮');
wd.sound();
</script>
类的继承

​ 一个类中有另一个类的属性和方法 这就是继承

<script>
// 定义一个基类   也叫父类
class Worker{
    constructor(name,money){
        this.name = name;
        this.money = money;
    }

    // 定义周报方法
    zb(){
        console.log(this.name + '的周报');
    }
    // 定义绩效的方法
    jx(){
        console.log(this.name + '的绩效是奖金加上' + this.money);
    }
}

// 派生类   子类
class Boss extends Worker{
    szb(){
        console.log(this.name + '在审核下属的周报');
    }
    sjx(){
        console.log(this.name + '在审核下属的绩效');
    }
}


let w = new Worker('Tom',35);
w.zb();
w.jx();

let b = new Boss('Mary',10);
b.zb();
b.jx();
b.szb();
b.sjx();
</script>
方法的重写

​ 方法的重写 也叫方法的覆写 所以说 一般情况下我们在子类中重写方法的时候

​ 都是使用方法名把父类的方法覆盖掉 直接重新定义

<script>
// 定义一个基类   也叫父类
class Worker{
    constructor(name,money){
        this.name = name;
        this.money = money;
    }
    // 定义周报方法
    zb(){
        console.log(this.name + '的周报');
    }
    // 定义绩效的方法
    jx(){
        console.log(this.name + '的绩效是奖金加上' + this.money);
    }
}

// 派生类   子类
class Boss extends Worker{
    szb(){
        console.log(this.name + '在审核下属的周报');
    }
    sjx(){
        console.log(this.name + '在审核下属的绩效');
    }
    jx(){
        console.log(this.name + '说:我的绩效和你们的绩效不一样  我是按照季度算的');
        console.log('我的绩效是零花钱');
    }
}


let w = new Worker('Tom',35);
w.zb();
w.jx();

let b = new Boss('Mary',10);
b.zb();
b.jx();
b.szb();
b.sjx();
</script>
继承构造器

​ 但是 我们注意一下 有一个方法不能覆写 那就是构造器方法

​ 这个方法可以继承 如果说父类中的构造器无法满足子类中的需求了 那么我们可以在子类中重新定义构造器

​ 但是在重新定义构造器的时候 必须将父类的构造器方法继承过来

​ 继承构造器 使用关键字super

​ 使用super继承父类的构造器 并且 我们需要继承父类构造器中的所有的参数

<script>
class Worker{
    constructor(name,money){
        this.name = name;
        this.money = money;
    }
    zb(){
        console.log(this.name + '的周报');
    }
}

// 继承构造器
class Boss extends Worker{
    // 方法的覆写  失败
    // constructor(name,money,age) {
    //     console.log(name,money,age);
    // }
    // 方法的重写   不带已继承参数
    // constructor(age) {
    //     this.age = age;
    // }
    constructor(name,money,age) {
        super(name,money);
        this.age = age;
    }
    szb(){
        console.log(this.name + '在审核下属的周报');
    }
    sjx(){
        console.log(this.name + '在审核下属的绩效');
        console.log(this.name + "年龄是" + this.age + "收取是" + this.money);
    }
}

let w = new Worker('Tom',35);
w.zb();

let b = new Boss('Mary',10,35);
b.sjx();
</script>
静态方法

​ 静态方法是存储在数据段的内存 他对每一个段都是开放的

​ 所以说 使用静态方法不需要实例化 就可以直接使用

​ 静态方法的运行效率要比常规的对象方法快55%

​ 定义静态方法的时候 我们需要 static 修饰的方法

​ 使用静态方法的时候 使用 类名.方法名()

​ 静态方法注意事项

​ 在静态方法中 不能使用非静态成员 如果想使用成员 那么必须将成员设定为静态成员

​ 不能使用构造器初始化静态成员

<script>
class Car{
    constructor (name,color){
        // this.name = name;
        // this.name = 'Tom'
        this.color = color;
    }
    static name = 'Tom'

    // 定义静态方法
    static start() {
        // console.log(this.name + '汽车已经启动');
        console.log(Car.name + '汽车已经启动');
    }

    stop(){
        Car.start();
        console.log('停车');
    }
}

// 使用静态方法  不需要实例化
Car.start();

let c = new Car('benz','黑色');
c.stop();
</script>

16. ES6模块

​ 在ES5中 我们使用的模块是使用script标签中的src属性 引入的一个JS文件

​ 我们使用scr引入的模块 有一些问题

​ 不安全 因为我们可以修改以内模块的内部数据

​ 所以说 在ES6中 我们再次使用模块的时候避免了这些问题

​ 现在可以将我们不需要的内容进行隐藏 阻止程序引入

​ ES6模块引入主要有两个部分

​ 1.模块的引入 使用import 和 from

​ 2.模块的暴露 使用export

​ 只有暴露的内容才能被引入 只有引入的内容才可以使用

​ 模块引入注意事项

​ 1.必须在服务器中进行

​ 2.必须在script标签中添加type="module"属性

JS代码

// 第一种暴露方式
// let username = 'amdin';
// let password = '123';

// let fun = ()=>{
//     console.log('这是模块中的函数');
// }

// let arr = [11,33,55,66,99,88];

// let obj = {
//     name : 'Tom',
//     age : 18,
//     sex : '男',
//     username,
//     password
// }

// export {
//     arr,
//     obj,
//     fun
// }

// 第二种暴露方式
export let username = 'amdin';
export let password = '123';

export let fun = ()=>{
    console.log('这是模块中的函数');
}

let arr = [11,33,55,66,99,88];

export let obj = {
    name : 'Tom',
    age : 18,
    sex : '男',
    username,
    password
}

html代码

<script type="module">
// import {arr,obj,fun} from "./13.public.js";

// console.log(username);
// console.log(password);
// console.log(arr);
// console.log(obj);
// fun();
// username = 123;
// console.log(username);


// 第二种方式
import {username,password,obj,fun} from "./13.public.js";

console.log(username);
console.log(password);
console.log(obj);
fun();
</script>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值