let

  1. /*
  2. let 声明的变量有几个特点:
  3. 1. 不允许重复声明
  4. */
  5. //2. 块儿级作用域 全局, 函数, eval
  6. // if else while for 里边声明在外部无法访问
  7. {
  8. var boy = '罗志祥'; //{}没有块级作用于,var的变量会往全局的window中添加,所有外部能访问
  9. let girl = '周扬青'; //let只能在代码块中有效
  10. }
  11. console.log(girl); //罗志祥
  12. console.log(girl); //报错
  13. //3. 不存在变量提升
  14. console.log(song);
  15. var song = '时间管理'; //可以 输出undefined
  16. let song = '恋爱达人'; //报错
  17. //4. 不影响作用域链
  18. {
  19. let school = '尚硅谷';
  20. function fn(){
  21. console.log(school); //虽然是块级作用于 但不影响作用域链,这里依然可以输出
  22. }
  23. fn();
  24. }

const

  1. //1. 一定要赋初始值
  2. const A;
  3. //2. 一般常量使用大写(潜规则)
  4. const a = 100;
  5. //3. 常量的值不能修改
  6. SCHOOL = 'ATGUIGU';
  7. //4. 块儿级作用域
  8. {
  9. const PLAYER = 'UZI';
  10. }
  11. console.log(PLAYER);
  12. //5. 对于数组和对象的元素修改, 不算做对常量的修改, 不会报错
  13. // 常量指向的地址没有改变 所有不会报错
  14. const TEAM = ['UZI','MXLG','Ming','Letme'];
  15. TEAM.push('Meiko');

箭头函数

  1. //1. this 是静态的. this 始终指向函数声明时所在作用域下的 this 的值
  2. //而非箭头函数则指向调用它的对象所在作用域
  3. function getName(){
  4. console.log(this.name);
  5. }
  6. let getName2 = () => {
  7. console.log(this.name);
  8. }
  9. //设置 window 对象的 name 属性
  10. window.name = '尚硅谷';
  11. const school = {
  12. name: "ATGUIGU"
  13. }
  14. //直接调用
  15. getName(); //尚硅谷
  16. getName2(); //尚硅谷 getName2当前所在作用域是window (this 始终指向函数声明时所在作用域下的 this 的值)
  17. //call 方法调用
  18. getName.call(school); //ATGUIGU(指向调用它的作用域)
  19. getName2.call(school); //尚硅谷(始终指向声明时)
  20. //2. 不能作为构造实例化对象
  21. let Person = (name, age) => {
  22. this.name = name;
  23. this.age = age;
  24. }
  25. //let me = new Person('xiao',30); //报错
  26. //3. 不能使用 arguments 变量
  27. let fn = () => {
  28. console.log(arguments); //arguments is not defined
  29. }
  30. fn(1,2,3);

箭头函数实践

this指向 :

  • 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调
  • 箭头函数不适合与 this 有关的回调. 事件回调, 对象的方法

箭头函数的注意点:

  1. 如果形参只有一个,则小括号可以省略
  2. 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的 执行结果
  3. 箭头函数 this 指向声明时所在作用域下 this 的值,如果this为undefined 则往上级找
  4. 箭头函数不能作为构造函数实例化
  5. 不能使用 arguments

    1. <body>
    2. <div id="ad"></div>
    3. <script>
    4. //需求-1 点击 div 2s 后颜色变成『粉色』
    5. //获取元素
    6. let ad = document.getElementById('ad');
    7. //绑定事件
    8. ad.addEventListener("click", function(){
    9. //不使用箭头函数时 保存 this 的值
    10. // let _this = this;
    11. //定时器
    12. setTimeout(() => {
    13. //修改背景颜色 this
    14. // console.log(this);//不使用箭头函数->window
    15. // _this.style.background = 'pink';
    16. this.style.background = 'pink';
    17. }, 2000);
    18. });
    19. //需求-2 从数组中返回偶数的元素
    20. const arr = [1,6,9,10,100,25];
    21. // const result = arr.filter(function(item){
    22. // if(item % 2 === 0){
    23. // return true;
    24. // }else{
    25. // return false;
    26. // }
    27. // });
    28. const result = arr.filter(item => item % 2 === 0);
    29. console.log(result);
    30. // 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调
    31. // 箭头函数不适合与 this 有关的回调. 事件回调, 对象的方法
    32. {
    33. name:'123',
    34. show:function(){
    35. console.log(this.name) //此时this指向该对象
    36. },
    37. show:()=>{
    38. console.log(this.name) //因为{}不能产生作用域, 此时this指向window
    39. }
    40. }
    41. </script>
    42. </body>

    函数参数默认值

//ES6 允许给函数参数赋值初始值
//1. 形参初始值 具有默认值的参数, 一般位置要靠后(潜规则)
// function add(a,b,c=10) {
//     return a + b + c;
// }
// let result = add(1,2);
// console.log(result);

//2. 与解构赋值结合
function connect({host="127.0.0.1", username,password, port}){
    console.log(host)
    console.log(username)
    console.log(password)
    console.log(port)
}
connect({
    host: 'atguigu.com',
    username: 'root',
    password: 'root',
    port: 3306
})

rest参数(剩余参数) ES6+ES9

rest 译 = 其余

ES6

  1. 用于获取函数的实参,用来代替 arguments
  2. 作为参数数组 可用数组方法filter some every map ```javascript // ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments // 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); // 1 console.log(b); // 2 console.log(args); // [3,4,5,6] } fn(1,2,3,4,5,6);

<a name="LK9PM"></a>
## ES9 
为对象提供了像数组一样的 rest 参数
```javascript
//rest 参数
function connect({host, port, ...user}){
    console.log(host); // 127.0.0.1
    console.log(port); // 3306
    console.log(user); //{username: "root", password: "root", type: "master"}
}

connect({
    host: '127.0.0.1',
    port: 3306,
    username: 'root',
    password: 'root',
    type: 'master'
});

spread 扩展运算符(…) ES6+ES9

spread 译 = 扩展

扩展运算符(spread)也是三个点(…)。它好比 rest 参数的逆运算,将个数组转为用逗号分隔的参数序列,对数组进行解包。

ES6 - 数组合并/克隆

  1. 数组合并
  2. 数组克隆
  3. 伪数组转真数组 ```javascript //1. 数组的合并 情圣 误杀 唐探 const kuaizi = [‘王太利’,’肖央’]; const fenghuang = [‘曾毅’,’玲花’]; // const zuixuanxiaopingguo = kuaizi.concat(fenghuang); const zuixuanxiaopingguo = […kuaizi, …fenghuang]; console.log(zuixuanxiaopingguo);

//2. 数组的克隆(浅拷贝) const sanzhihua = [‘E’,’G’,’M’]; const sanyecao = […sanzhihua];// [‘E’,’G’,’M’] console.log(sanyecao);

//3. 将伪数组转为真正的数组 const divs = document.querySelectorAll(‘div’); const divArr = […divs]; console.log(divArr);//

<a name="ya4r8"></a>
## ES9 - 对象合并/克隆

1. 对象合并
1. 对象克隆
```javascript
//对象合并
const nameOne = {
    q: 'ivy'
}

const nameTwo = {
    w: 'Amanda'
}

const nameAll = {...nameOne, ...nameTwo};
//{q: "ivy", w: "Amanda"}
console.log(nameAll)

//对象克隆
const nameThree = {
    q: 'ivy'
}
console.log({...nameThree})

symbol

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol 特点

  1. Symbol 的值是唯一的,用来解决命名冲突的问题
  2. Symbol 值不能与其他数据进行运算
  3. Symbol 定义 的 对象属 性 不能 使 用 for…in 循 环遍 历 ,但 是可 以 使 用 Reflect.ownKeys 来获取对象的所有键名

    基本用法

    ```javascript //创建Symbol let s = Symbol(); console.log(s, typeof s); //Symbol() “symbol” let s2 = Symbol(‘尚硅谷’); let s3 = Symbol(‘尚硅谷’); console.log(s2===s3); //false //Symbol.for 创建 let s4 = Symbol.for(‘尚硅谷’); let s5 = Symbol.for(‘尚硅谷’); console.log(s4===s5); //true

//不能与其他数据进行运算 // let result = s + 100; // let result = s > 100; // let result = s + s;

//七种数据类型 // USONB you are so niubility // u undefined // s string symbol // o object // n null number // b boolean

<a name="bKr6f"></a>
## 向对象中添加方法
```javascript
//1.向对象中添加方法
//方式一 
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)

内置属性

这里只介绍几种用法,详细参考阮一峰

//1.hasInstance当其他对象使用 instanceof 运算符,判断是否为该对
象的实例时,会调用这个方法
class Person{
    static [Symbol.hasInstance](param){
        console.log(param);
        console.log("我被用来检测类型了");
        return false;
    }
}

let o = {};

console.log(o instanceof Person);
//2.对象的 Symbol.isConcatSpreadable 属性等于的是一个
布尔值,表示该对象用于 Array.prototype.concat()时,
是否可以展开。
const arr = [1,2,3];
const arr2 = [4,5,6];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr.concat(arr2));

迭代器(遍历)iterator

遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提 供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。

基本原理和适用对象

  1. ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费
  2. 原生具备 iterator 接口的数据(可用 for of 遍历)
    1. Array
    2. Arguments
    3. Set
    4. Map
    5. String
    6. TypedArray
    7. NodeList
  3. 工作原理
    • 创建一个指针对象,指向当前数据结构的起始位置
    • 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
    • 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
    • 每调用 next 方法返回一个包含 value 和 done 属性的对象

image.png
注: 需要自定义遍历数据的时候,要想到迭代器。

迭代器自定义遍历对象

//声明一个对象
const banji = {
    name: "终极一班",
    stus: [
        'xiaoming',
        'xiaoning',
        'xiaotian',
        'knight'
    ],
    [Symbol.iterator]() {
        //索引变量
        let index = 0;
        //
        let _this = this;
        return {
            next: function () {
                if (index < _this.stus.length) {
                    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);
}

entrise()

image.png
image.png

生成器 function * fnName()

生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同

基本原理和使用

代码说明:

    • 的位置没有限制
  1. 生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到 yield 语句后的值
  2. yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next 方法,执行一段代码
  3. next 方法可以传递实参,作为 yield 语句的返回值
    ```javascript //生成器其实就是一个特殊的函数 //异步编程 纯回调函数 node fs ajax mongodb //函数代码的分隔符 function * gen(){ // console.log(111); yield ‘一只没有耳朵’; // console.log(222); yield ‘一只没有尾部’; // console.log(333); yield ‘真奇怪’; // console.log(444); }

let iterator = gen(); console.log(iterator.next()); //{value: “一只没有耳朵”, done: false} console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next());//{value: undefined, done: true}

//遍历 for(let v of gen()){ console.log(v); }

<a name="xqi0j"></a>
## 参数
next 方法可以传递实参,作为 yield 语句的返回值<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/1624878/1624867713356-ed569392-3974-4a77-9217-ba43e40a557c.png#clientId=u94c8f321-040b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=290&id=ud85497cb&margin=%5Bobject%20Object%5D&name=image.png&originHeight=579&originWidth=1082&originalType=binary&ratio=2&rotation=0&showTitle=false&size=128946&status=done&style=none&taskId=u474f21ab-26f5-4897-9e76-79fe314c1f1&title=&width=541)
<a name="XxjIt"></a>
## 案例一 : 解决回调地狱
```javascript
// 异步编程  文件操作 网络操作(ajax, request) 数据库操作
// 1s 后控制台输出 111  2s后输出 222  3s后输出 333 
// 回调地狱
// setTimeout(() => {
//     console.log(111);
//     setTimeout(() => {
//         console.log(222);
//         setTimeout(() => {
//             console.log(333);
//         }, 3000);
//     }, 2000);
// }, 1000);

//使用生成器解决回调地狱
function one(){
    setTimeout(()=>{
        console.log(111);
        iterator.next();
    },1000)
}

function two(){
    setTimeout(()=>{
        console.log(222);
        iterator.next();
    },2000)
}

function three(){
    setTimeout(()=>{
        console.log(333);
        iterator.next();
    },3000)
}

function * gen(){
    yield one();
    yield two();
    yield three();
}

//调用生成器函数
let iterator = gen();
iterator.next();

案例二 : 异步获取数据(模拟获取 -> 用户数据 -> 订单数据 -> 商品数据)

利用next 方法可以传递实参,作为 yield 语句的返回值, 将数据传递给下一个next实现模拟过程

//模拟获取  用户数据  订单数据  商品数据 
function getUsers(){
    setTimeout(()=>{
        let data = '用户数据';
        //调用 next 方法, 并且将数据传入
        iterator.next(data);
    }, 1000);
}

function getOrders(){
    setTimeout(()=>{
        let data = '订单数据';
        iterator.next(data);
    }, 1000)
}

function getGoods(){
    setTimeout(()=>{
        let data = '商品数据';
        iterator.next(data);
    }, 1000)
}

function * gen(){
    let users = yield getUsers();
    console.log(users); //用户数据
    let orders = yield getOrders();
    console.log(orders); //订单数据
    let goods = yield getGoods();
    console.log(goods); //商品数据
}

//调用生成器函数
let iterator = gen();
iterator.next();

集合Set()

ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯 一的,集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of…』进 行遍历
集合的属性和方法:

  1. size 返回集合的元素个数
  2. add 增加一个新元素,返回当前集合
  3. delete 删除元素,返回 boolean 值
  4. has 检测集合中是否包含某个元素,返回 boolean 值 5) clear 清空集合,返回 undefined

    基本使用

    ```javascript //声明一个 set let s = new Set(); let s2 = new Set([‘大事儿’,’小事儿’,’好事儿’,’坏事儿’,’小事儿’]);

//元素个数 // console.log(s2.size); //添加新的元素 // s2.add(‘喜事儿’); //删除元素 // s2.delete(‘坏事儿’); //检测 // console.log(s2.has(‘糟心事’)); //清空 // s2.clear(); // console.log(s2);

// for(let v of s2){ console.log(v); }

<a name="wcOYP"></a>
## 案例 去重/交集/并集/差集
```javascript
let arr = [1,2,3,4,5,4,3,2,1];
//1. 数组去重
let result = [...new Set(arr)];
console.log(result);
//2. 交集
let arr2 = [4,5,6,5,6];
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);

Map

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键” 的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。
Map 的属 性和方法:

  1. size 返回 Map 的元素个数
  2. set 增加一个新元素,返回当前 Map
  3. get 返回键名对象的键值
  4. has 检测 Map 中是否包含某个元素,返回 boolean 值
  5. clear 清空集合,返回 undefined
    ```javascript //声明 Map let m = new Map();

//添加元素 m.set(‘name’,’尚硅谷’); m.set(‘change’, function(){ console.log(“我们可以改变你!!”); }); let key = { school : ‘ATGUIGU’ }; m.set(key, [‘北京’,’上海’,’深圳’]);

//size // console.log(m.size);

//删除 // m.delete(‘name’);

//获取 // console.log(m.get(‘change’)); // console.log(m.get(key));

//清空 // m.clear();

//遍历 for(let v of m){ console.log(v); }

![image.png](https://cdn.nlark.com/yuque/0/2021/png/1624878/1624939058722-9adece34-713c-4138-822f-9022a698aa0e.png#clientId=u0e0f86ca-c8bf-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=131&id=u0edec596&margin=%5Bobject%20Object%5D&name=image.png&originHeight=262&originWidth=832&originalType=binary&ratio=2&rotation=0&showTitle=false&size=40353&status=done&style=none&taskId=u7c400b6c-a5c0-48a0-a42e-96e1c399ee9&title=&width=416)
<a name="KGfoy"></a>
# 对象拓展方法
<a name="bGj2P"></a>
## Object.is判断两个值是否完全相等 
```javascript
console.log(Object.is(120, 120));// true 
console.log(Object.is(-0, 0));// false
console.log(Object.is(NaN, NaN));// true
console.log(NaN === NaN);// false

Object.assign 对象的合并

const config1 = {
    name: 'Dan',
    age: '20',
    hobby:'sing'
};
const config2 = {
    name: 'Amanda',
    age: '25'
}
//{name: "Amanda", age: "25", hobby: "sing"}
console.log(Object.assign(config1, config2));

ES8 - Object.keys和Object.values 和 Object.entries

  1. Object.keys()方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for…in 循环遍历该对象时返回的顺序一致

image.png

  1. Object.values()方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for…in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。

image.png

  1. Object.entries()方法返回一个给定对象自身可遍历属性 [key,value] 的数组

image.png

ES8 - Object.getOwnPropertyDescriptors

该方法返回指定对象所有自身属性的描述对象

const school = {
    name:"尚硅谷",
    cities:['北京','上海','深圳'],
    xueke: ['前端','Java','大数据','运维']
};

//对象属性的描述对象
console.log(Object.getOwnPropertyDescriptors(school));

//上边方法返回如下创建对象时设置属性特性,用于深拷贝
const obj = Object.create(null, {
    name: {
        //设置值
        value: '尚硅谷',
        //属性特性
        writable: true,
        configurable: true,
        enumerable: true
    } 
});
console.log(obj)

image.png

Object.setPrototypeOf 设置原型对象 Object.getPrototypeof

const school = {
    name: '尚硅谷'
}
const cities = {
    xiaoqu: ['北京','上海','深圳']
}
Object.setPrototypeOf(school, cities);
console.log(Object.getPrototypeOf(school));
console.log(school);

数值扩展

二进制和八进制

ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。

//1. 二进制和八进制
let b = 0b1010; //2 - 10
let o = 0o777; //8 - 511
let x = 0xff; //16 - 255

Number.isFinite() 与 Number.isNaN()

Number.isFinite() 用来检查一个数值是否为有限的
Number.isNaN() 用来检查一个值是否为 NaN

//isFinite
console.log(Number.isFinite(100)); //true
console.log(Number.isFinite(100/0)); //false
console.log(Number.isFinite(Infinity)); //false Infinity无穷数
//NaN
console.log(Number.isNaN(123)); //false
console.log(Number.isNaN(1/'我')); //true

Number.parseInt() 与 Number.parseFloat()

ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变。

console.log(Number.parseInt('5211314love')); //5211314
console.log(Number.parseFloat('3.1415926神奇')); //3.1415926

Math.trunc

用于去除一个数的小数部分,返回整数部分。

console.log(Math.trunc(3.5)); //3

Number.isInteger()

用来判断一个数值是否为整数

console.log(Number.isInteger(5)); //true
console.log(Number.isInteger(2.5)); //false

Number.sing()

用来判断一个数到底是 正数 负数 还是零

console.log(Math.sign(100)); //1
console.log(Math.sign(0)); //0
console.log(Math.sign(-20000)); //-1

Number.EPSILON

Number.EPSILON 是 JavaScript 表示的最小精度
EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16

function equal(a, b){
if(Math.abs(a-b) < Number.EPSILON){
    return true;
}else{
    return false;
}
}
console.log(0.1 + 0.2 === 0.3); //false
console.log(equal(0.1 + 0.2, 0.3)); //true