ES6-狮子狗特供版(log’s KaMingSAMA)

376 阅读10分钟

一、let 和 const

1-1 let和const

  1. let和const是什么
    声明变量或声明常量
    var声明变量
    let代替var,声明变量
    const声明常量constant

  2. let和const的用法
    和var一样

  3. 什么是变量,什么是常量 var、let声明的就是变量,变量一旦初始化之后,还可以重新赋值
    const声明的就是常量,常量一旦初始化,就不能重新赋值了,否则就会报错

1-2 const

  1. 为什么需要const?
    就是为了那些一旦初始化就不希望重新赋值的情况设计的

  2. const的注意事项
    2.1 使用const声明变量,一旦声明,就必须立即初始化,不能留到以后赋值
    2.2 const声明的常量,允许在不重新赋值的情况下修改它的值

    const person = {username:"Alex"};
    person.username = "ZhangSan";
    console.log(person);
  1. 什么时候用const,什么时候用let
    当你不知道使用const还是let的时候,建议使用const,在之后的某一天如果想要修改的时候,他会报错,这样之后也好修改。

1-3 let、const与var的区别

  1. 重复声明
    已经存在的变量或常量,又声明了一遍
    var允许重复声明,let、const不允许
  2. 变量提升
    var会提升变量的声明到当前作用域的顶部
    相当于
    var a;
    console.log(a);
    a = 1;
    console.log(a);

let、const不存在变量提升
养成良好的编程习惯,对于所有的变量或常量,做到先声明,后使用。

  1. 暂时性死区
    只要作用域内存在let、const,它们所声明的变量或常量就自动"绑定"这个区域,不再受到外部作用域的影响
    //let、const存在暂时性死区
    let a = 2;
    let b = 1;
    function func() {
        console.log(a);
        let a = 1;
    }
    func()
  1. window对象的属性和方法 全局作用域中,var声明的变量,通过function声明的函数,会自动变成window对象的属性或方法
    let、const不会

1-4 块级作用域

  1. 什么是块级作用域
    var没有块级作用域,let/const有块级作用域
  2. 作用域链
image.png
作用域链:内层作用域->外层作用域->...->全局作用域
3. 有哪些块级作用域


{}
for(){}
while(){}
do{}while()
if(){}
switch(){}

1-5 let和const的应用

image.png

image.png

image.png

二、模板字符串

2-1 模板字符串

  1. 认识模板字符串
const username2 = `alex`;
console.log(username1,username2,username1===username2)
  1. 模板字符串与一般字符串的区别
const person = {
    username:'Alex',
    age:18,
    sex:'male'
};
const info = 
'我的名字是:'+
person.username +
',今年:' +
person.age +
'岁了';
console.log(info)

const info = `我的名字是:${person.username},
性别:${person.sex},
今年${person.age}岁了`
console.log(info);

//和其他东西一起使用的时候,使用模板字符串,方便注入
//其他情况下使用模板字符串或一般字符串都行

2-2 模板字符串的注意事项

  1. 输出多行字符串
    一般字符串
const info = `第1行\n第2行`
console.log(info);

//模板字符串
const info = `第1行\n第2行`

const info = `第1行
第2行`
console.log(info);
//模板字符串中,所有的空格、换行或缩进都会被保留在输出之中
  1. 输出`和\等特殊字符
const info = `\``;
console.log(info);


  1. 模板字符串的注入
    ${}
const username = 'alex';
const person = {age:18,sex:'male'};
const getSex = function(sex){
    return sex === 'male'?'男':'女';
};

const info =`${username},${person.age},${getSex(person.sex)}`;
console.log(info);

只要最终可以得出一个值的就可以通过${}注入到模板字符串中

2-3 模板字符串的应用

image.png

三、箭头函数

3-1 箭头函数

  1. 认识箭头函数
  const add = (x,y)=>{
      return x + y;
  };
  console.log(add(1,1))     
  1. 箭头函数的结构
    const/let 函数名 = 参数 => 函数体

  2. 如何将一般函数改写成箭头函数

        // 声明形式
        function add(){}

        // 声明形式->函数表达式形式
        const add = function () {};

        // 函数表达式形式->箭头函数
        const add = () => {};

3-2 箭头函数的注意事项

  1. 单个参数
const add = (x) => {
    return x + 1
};
//单个参数可以省略圆括号
const add = x => {
    return x + 1;
}
console.log(add(1));

//无参数或多个参数不能省略圆括号
const add = () => {
    return 1 + 1;
};
const add = (x,y) => {
    return x + y;
};
console.log(add(1,1));
  1. 单行函数体
// 单行函数体可以同时省略{}和return
const add = (x,y) => {
    return x + y;
};

const add = (x,y) => x + y
console.log(add(1,1));

// 多行函数体不能再化简了
const add = (x,y) => {
    const sum = x + y
    return sum;
};
  1. 单行对象
const add = (x,y) => {
    return {
        value: x + y
    }
}
const add = (x,y) => ({
    value: x + y;
    return undefind;
})

// 如果箭头函数返回单行对象,可以在{}外面加上(),让浏览器不在认为那是函数体的花括号

const add = (x,y) => [x,y];

console.log(add(1,1))

3-3 this指向1

  1. 全局作用域中的this指向
console.log(this) //window
  1. 一般函数(非箭头函数)中的this指向
//'use strict'
function add(){
    console.log(this);
}


// 严格模式就指向undefined
add() //undefined -> window(非严格模式下)
// window.add();

const calc = {
    add:add
};
// calc.add(); // calc
const adder = calc.add;
adder(); // undefined -> window(非严格模式下)

document.onclick = function() {
    console.log(this);
};

function Person(username) {
    this.username = username;
    console.log(this);
}

const p = new Person('Alex'); //构造函数指向的是他的实例对象

//只有在函数调用的时候this指向才确定,不调用的时候,不知道指向谁

//this指向和函数在哪儿调用没关系,只和谁在调用有关

3-4 this指向2

  1. 箭头函数中的this指向
    箭头函数没有自己的this
const calc = {
    add:() => {
        console.log(this)
    }
};
calc.add();//window

3-5 不适用箭头函数的场景

  1. 作为构造函数
    箭头函数没有this
 const Person = () => {};
       new Person();
  1. 需要this指向调用对象的时候

  2. 需要使用arguments的时候
    箭头函数中没有arguments

3-6 箭头函数的应用

 <button id="btn">开始</button>
    <span id="result">0</span>
    <script>
        const btn = document.getElementById('btn');
        const result = document.getElementById('result');

        const timer = {
            time:0,
            strat:function(){
                console.log(this);
                // const th
                btn.addEventListener('click',() => {
                    setInterval(()=>{
                        this.time++;
                        result.innerHTML = this.time;
                        console.log(this);
                    },1000)
                },false)
            }
        }
        timer.strat();
    </script>

数组的解构赋值

4-1 数组的解构赋值

  1. 认识解构赋值
   const arr = [1,2,3];
   const a = arr[0]
   const a = arr[0]
  1. 什么是解构赋值
    解构某一数据的结构,将我们想要的东西提取出来,赋值给变量或常量。

4-2 数组解构赋值的原理

  1. 模式(结构)匹配
    [] = [1,2,3];
  2. 索引值相同的完成赋值
   [a,b,c] = [1,2,3];
   console.log(a,b,c);
   
   const = [1,[2,4,5],3]
   const [a,[,,b],c] = [1,[2,4,5],3];
   console.log(a,b,c);

4-3 数组解构赋值的默认值

  1. 默认值得基本用法
        // const [a,[,,b],c] = [1,[2,4,5],3];
        // console.log(a,b,c);

        // const [a,b] = []
        const [a,b] = [undefined,undefined];
        console.log(a,b);
  1. 默认值的生效条件
    只有当一个数组成员严格等于(===)undefined时,对应的默认值才会生效。

3.默认值表达式
如果默认值是表达式,默认值表达式是惰性求值的

        const func = () => {
            console.log('我被执行了');
            return 2;
        };
        const [x=func()] = [1]
        console.log(x);

4-4 数组解构赋值的应用

  1. 常见的类数组的解构赋值
        function func() {
            console.log(arguments);
        }
        func();
        func(1,2)
  1. 函数参数的解构赋值
 const array = [1,1];
 // const add = arr => arr[0] + arr[1];
 const add = ([x,y]) => x + y
 // console.log(add(array));
 console.log(add([]));
  1. 交换变量的值
 let x = 1;
        let y = 2;

        // let tmp = x;
        // x = y;
        // y = tmp;
        // console.log(x,y);

        [x,y] = [y,x];
        console.log(x,y);

五、对象的解构赋值

5-1 对象的解构赋值

  1. 模式(结构)匹配
    {} = {}
  2. 属性名相同的完成赋值
// 属性名相同赋值
        // const {age,username} = {username:'Alex',age:18}
        // const {'age':age,'username':username} = {username:'Alex',age:18}
        // console.log(age,username);

        //取别名
        const {age:age,username:uname} = {
            username:'Alex',age:18}
        console.log(age,uname);

5-2 对象解构赋值的注意事项

  1. 默认值的生效条件
    对象的属性值严格等于undefined时,对应的默认值才会生效
        //对象渲染的注意事项
        //属性名添加默认值时,注意是写等号
        const {username = 'Zhangsan',age = 0} = {username:'alex'}
        console.log(username,age);
  1. 默认值表达式
    如果默认值是表达式,,默认值表达式是惰性求值的

  2. 将一个已经声明的变量用于解构赋值

        // let x = 2;
        // ({x} = {x: 1})
        // console.log(x);
        // [x] = [1];
        // console.log(x);
  1. 可以取到继承的属性
 const {toString} = {}
        console.log(toString);
        //对象toString继承自Object的,在Object的prototype上

5-3 对象解构赋值的应用

  1. 函数参数的解构赋值
        const logPersonInfo = ({age,username}) => console.log(username,age);
        logPersonInfo({username:'alex',age:18});
  1. 复杂的嵌套
        const obj = {
            x:1,
            y:[2,3,4],
            z:{
                a:5,
                b:6
            }
        };
        // const {x,y,z} = obj;
        // console.log(x,y,z);
        const {
            y,
            y:[,yy]
        } = obj
        console.log(yy,y);

5-4 其他数据类型的解构赋值

  1. 字符串的解构赋值

2.数值和布尔值的解构赋值
等号右边的值转为对象

3.undefined 和null的解构赋值
由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错

六、对象字面量的增强

6-1 方括号语法

  1. 方括号语法的用法
const prop = 'age';
const person = {};

// person.prop = 18;
person[prop] = 18;

const person = {
    [prop]:18
}

console.log(person);

2.方括号中可以放什么
// ${}
// [值或通过计算可以得到值的(表达式)]

const prop = 'age';
const func = () => 'age';
const person = {
   // [prop]:18
   // ['sex']:'male'
   // [func()]:18
}

console.log(person)

3.方括号语法和点语法的区别
点语法是方括号语法的特殊形式
const person ={};
// person.age 等价于person['age']

// 属性名由数字、字母、下划线以及$构成,并且数字还不能打头的时候可以使用点语法

// age18_$ √
// 18age x
// 合法标识符可以用来作为变量或常量名

// 当你的属性或方法名是合法标识符时,可以使用点语法,其他情况下请使用方括号语法

6-2 属性和方法的简洁表示法

//1. 对象字面量是什么
//实例化构造函数生成对象
const person = new Object();
person.age = 18;
person.speak = function () {};

// 对象字面量
// const person = {
    age:18,
    speak:function () {}
};

//2.属性的简洁表示法
//键名和变量或常量名一样的时候,可以只写一个
const age = 18
const person = {
    age
}

console.log(person);
// 3.方法的剪辑表示法
const person = {
    speack () {}
}
console.log(person)

七 函数参数的默认值

7-1 函数参数的默认值

// 1.认识函数参数的默认值
// 调用函数的时候传参了,就用传递的参数:如果没传参,就用默认值
//multiply(2,1);
//multiply(2);

// 2.函数参数默认值的基本用法
//(过去方法)
const multiply = (x,y) => {
    if(typeof y==='undefined') {
        y = 1;
    }
    return x * y
}
//(现在方法)
//const multiply = (x,y=1) => x*y;
console.log(multiply(2))

7-2 函数参数默认值的注意事项

// 1.默认值的生效条件
// 不传参数,或者明确的传递 undefined作为参数,只有这两种情况下,默认值才会生效
const multiply = (x,y = 1) => x * y;
console.log(multiply(2,0));
console.log(multiply(2,null));
console.log(multiply(2,undefined));
console.log(multiply(2));

// 2.默认值表达式
// 如果默认值是表达式,默认值表达式惰性求值的

// 3.设置默认值的小技巧
// 函数参数的默认值,最好从参数列表的右边开始设置
// console.log(multiply(undefined,2));

7-3 函数参数默认值的应用

// 1.接受很多参数的时候
const logUser = (username = 'ZhangSan',age = 0,sex = 'male')=>console.log(username,age,sex);
logUser('Alex',18,'male');
logUser();

// 2. 接受一个对象作为参数
//const logUser = options=>console.log(options.username,options.age,sex);

const logUser = ({username = 'ZhangSan',age = 0,sex = 'male'} = {}) => console.log(options.username,options.age,options.sex)
// logUser({
//    username:'alex',
//  age:18,
//  sex:'male'
// });
logUser({username:'alex'});
logUser({});
logUser();

八 剩余参数

8-1 剩余参数

// 1.认识剩余参数
const add = (x,y,z,...args) => {};

// 2. 剩余参数的本质
const add = (x,y,...args) => {
    console.log(x,y,args);
};
add(1,2,3);

//剩余参数永远是是个数组,即使没有值,也是空数组


8-2 剩余参数的注意事项

// 1. 箭头函数的剩余参数
// 箭头函数的参数部分即使只有一个剩余参数,也不能省略括号
//  const add = (...args) => {};

// 2. 使用剩余参数替代 arguments获取实际参数
// const add = function () {
//    console.log(arguments);
//}
const add = () => {
    console.log(arguments);
}
add(1,2);

//3. 剩余参数的位置
//剩余参数只能是最后一个参数,之后不能再有其他参数,否则会报错
const add = (x,...args,y) => {
    console.log(args);
}

8-3 剩余参数

// 1. 完成add函数
const add = (...args) => {
    let sum = 0;
    for(let i = 0;i < args.length:i++) {
        sum += args[i];
    }
    return sum
}

console.log(add(1,2,3));

// 2.与解构赋值结合使用
// 剩余参数不一定非要作为函数参数使用
// const [num,...args] = [1,2,3,4];
// 必须是最后一个
// const [...args,num] = [1,2,3,4];
console.log(numm,args);

//const func = ([num,...args]) => {};
//func([1,2,3]);

const {x,y,...z} = {a:3,x:1,y:2,b:4};
console.log(x,y,z)

九 数组的展开运算符

9-1 数组的展开运算符

// 1.认识展开运算符
// [3,1,2]
// Math.min

console.log(Math.min([3,1,2]));

// 2. 数组展开运算符的基本用法
// console.log(Math.min(...[3,1,2]))
//相当于
console.log(Math.min(...[3,1,2]));

9-2 区别剩余参数和展开运算符

// 1.根本区别
//展开运算符
// [3,1,2] -> 3,1,2

//剩余参数
//3,1,2 -> [3,1,2]

// 2.区别剩余参数和展开运算符

// 展开运算符
const add = (...args) => {
    console.log(...args)
};
add(1,2,3)

[...[1,2,3],4];
// [1,2,3] -> 1,2,3

9-3 数组展开运算符的应用

//1. 复制数组;
const a = [1,2];
//const b = a;
//a[0] = 3;
//console.log(b);

const c = [...a];
//const c = [1,2];
a[0] = 3;
console.log(a);
console.log(c);

// 2.合并数组
const a = [1,2];
const b = [3];
const c = [4,5];

console.log([...a,...b,...c]);

// 3.字符串转为数组
// 字符串可以按照数组的形式展开
// console.log(...'alex');

// 4. 常见的类数组转化为数组
// arguments
function func() {
    console.log([...arguments]);
}
func(1,2);

//NodeList
// console.log(document.querySelectorAll('p'));
// console.log([...document.querySelectorAll('p')].push)

十 对象的展开运算符

10-1 对象的展开运算符

// 1. 展开对象
// 对象不能直接展开,必须在{}中展开
const apple = {
    color:'红色',
    shape:'球形',
    taste:'甜'
}

//对象的展开:把属性罗列出来,用逗号分隔,放到一个{}中,构成新对象
console.log({...apple}) === apple;

// 2. 合并对象
const apple = {
    color:'红色',
    shape:'球形',
    taste:'甜'
};
//console.log({...pen});
//console.log({...apple,...pen});

//新对象拥有全部属性,相同属性,后者覆盖前者
//console.log({...pen,...apple});
//相当于
//console.log({
//    use:'写字',
//    color:'红色',
//    shape:'球形',
//    taste:'甜'
});


10-2 对象展开运算符的注意事项

// 1. 空对象的展开
// 如果展开一个空对象,则没有任何效果
// console.log({...{}});
// console.log(...{},a:1);

//2. 非对象的展开
//如果展开的不是对象,则会自动将其转为对象,再将其属性罗列出来
// console.log({...1});
// console.og(new Object(1));
// console.log({...undefined});
// console.log({...null});
// console.log({...true});

// 如果展开运算符后面是字符串,它会自动转成一个类似数组的对象,因此返回的不是空对象
// console.log({...'alex'});
// console.log([...'alex']);
// console.log(...'alex');

console.log({...[1,2,3]});

// 3.对象中对象属性的展开
// 不会展开对象中的对象属性
const apple = {
    feature:{
        taste:'甜'
    }
};
const pen = {
    feature:{
        color:'黑色',
        shape:'圆柱形'
    },
    use:'写字'
}

//console.log({...apple});
console.log({...apple,...pen});

//相当于
console.log({
    feature:{
        taste:'甜'
    }
    //下面的feature覆盖了上面的feature
    feature:{
        color:'黑色',
        shape:'圆柱形'
    },
    use:'写字'
})

10-3 对象展开运算符的应用

// 1. 复制对象
// const a = {x:1 , y:2};
// cosnt b = a;

// const c = {...a};
// console.log(c,c===a);

//2. 用户参数和默认参数
//add(1,2,3);

const logUser = userParam => {
    const deaultParam = {
        username:'ZhangSan',
        age:0,
        sex:'male'
    };
    
    //const param = {...defaultParam,...userParam};
    // console.log(param.username);
    const {username,age,sex} = {...
        defaultParam,...userParam};
        console.log(username,age,sex);
}

十一 Set

11-1 Set是什么

// 1.什么是Set
// 集合

[1,2];
// 数组是一系列有序的数据集合

//Set 是一系列无序、没有重复值的数据集合

//2.理解Set
console.log(1,2,1);
console.log(new Array(1,2,1));

cosnt s =  new Set();
s.add(1);
s.add(2);

//Set中不能有重复的成员
s.add(1);
console.log(s);

//Set没有下标去标示每一个值,所有Set是无序的,也不能像数组那样通过下标去访问Set的成员

11-2 Set实例的方法和属性

// 1. 方法
// add
const s = new Set();
s.add(1).add(2).add(2);
// console.log(s);

// has
console,log(s.has(1));
console.log(s.has(3));

//delete
S.delete(1);

//使用delete删除不存在的成员,什么都不会发生,也不会报错
// s.delete(3);
// console.log(S);

//clear
// s.clear
// console.log(s);

//forEach
console.log(s);
s.forEach(function(value,key,set) {
    // Set中value = key
    // console.log(value,key,set === s);
    console.log(this);
},document);

//按照成员添加进集合的顺序遍历


//2.属性
//size
console.log(s.size);

11-3 Set构造函数的参数

// 1.数组
        // const s = new Set([1,2,1]);
        // console.log(s);
        

        // // 2.字符串、arguments、NodeList、Set等
        // console.log(new Set('hi'));
        // function func() {
        //     console.log(new Set(arguments));
        // }
        // func(1,2,1);

        // console.log(new Set(document.querySelectorAll('p')));

        // const s = new Set([1,2,1]);
        // console.log(new Set(s) === s);
        // console.log(s);

11-4 Set构造函数的注意事项

//1.判断重复的方式
        // const s = new Set([1,2,1]);
        // const s = new Set([NaN,1,NaN])
        // console.log(s);

        // console.log(1 === 1);
        

        // Set对于重复值的判断基本遵循严格相等(===)
        // 但是对于NaN的判断与 === 不同,Set中NaN等于NaN

        // const s = new Set();
        // s.add({}).add({});
        // console.log({}==={});
        // console.log(s);
        

        //2. 什么时候使用Set
        //  ① 数组或字符串去重时
        //  ② 不需要通过下标访问,只需要遍历时
        //  ③ 为了使用Set提供的方法和属性时(add delete clear has forEach sizs等)

11-5 Set的应用

 // 1. 数组去重
        // [1,2,1]
        // const s = new Set([1,2,1]);
        // console.log(s);
        // // s.forEach

        // console.log([...s]);

        // 2.字符串去重
        //'abbacbd'
        // const s = new Set('abbacbd');
        // console.log([...s].join(''));
        

        // console.log([...new Set('abbacbd')].join(''));

        //3. 存放 DOM 元素
        // console.log(document.querySelectorAll('p'));
        
        // const s = new Set(document.querySelectorAll('p'));
        // s.forEach((value) => {
        //     console.log(value);
        //     value.style.color = 'red';
        //     value.style.backgroundColor = 'yellow';
        // });

十二 Map

12-1 Map是什么

// 12 Map
        // Map是什么
        // 映射

        // Map和对象都是键值对的集合

        // 键 -> 值, key -> value
        // const person= {
        //     name:'alex',
        //     age:18,
        // }

        // const m = new Map();
        // m.set('name','alex');
        // m.set('age',18);
        // console.log(m);

        //2. Map和对象的区别
        // 对象一般用字符串当作键
        // const obj = {
        //     name:'alex',
        //     true:'true',
        //     [{}]:'object'
        // }
        // console.log(obj);
        // console.log({}.toString())

        // 基本的数据类型:数字、字符串、布尔值、undefined、null
        // 引用数据类型:对象([]、{}、函数、Set、Map等)
        // 以上都可以作为Map的键

        // const m = new Map();
        // m.set('name','alex');
        // m.set (true,'true');
        // m.set({},'object');
        // m.set(new Set([1,2]),'set');
        // m.set(undefined,'undefined')
        // console.log(m);

12-2 Map实例的方法和属性

// 1.方法
        // set
        // const m = new Map();

        // //使用set添加的新成员,键如果已经存在,后添加的键值对覆盖已有的
        // m.set('age',18).set(true,'true').set('age',20);
        // console.log(m);

        // Map有set和get方法可以添加和获取
        // Set只有add可以添加不可以对单个键获取

        // get
        // console.log(m);
        // console.log(m.get('age'));
        
        // //get获取不存在的成员,返回undefined
        // console.log(m.get('true'));

        // // has
        // console.log(m.has('age'));

        // // delete
        // m.delete('age');
        // m.delete('name');

        // // 使用delete删除不存在的成员,什么都不会发生,也不会报错
        // console.log(m);

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

        // forEach
        // m.forEach (function(value,key,map) {
        //     console.log(value,key,map === m);
        //     console.log(this);
        // },document)

        // // 2. 属性
        // // size

        // // 对象没有类似的属性
        // console.log(m.size);

12-3 Map构造函数的参数

// 1. 数组
        // console.log(new Map(['name','alex','age']));

        // 只能传二维数组,而且必须体现出键和值

        // console.log(new Map([
        //     ['name','alex'],
        //     ['age',18]
        // ])
        // );

        // //2. Set、Map等
        // // Set
        // // Set中也必须体现出键和值

        // const s = new Set([
        //     ['name','alex'],
        //     ['age',18]
        // ])
        // console.log(s);

        // Map
        // const m1 = new Map([
        //     ['name','alex'],
        //     ['age',18]
        // ])
        // console.log(m1);
        // const m2 = new Map(m1);
        // console.log(m2,m2 === m1);

12-4 Map的注意事项

// 1. 判断键名是否相同的方式
        // 基本遵循严格相等(===)
        // 例外就是NaN,Map中NaN也是等于NaN
        // console.log(NaN === NaN);
        // const m = new Map();
        // m.set(NaN,1).set(NaN,2);
        // console.log(m);

        // // 2. 什么时候使用Map
        // // 如果只是需要 key -> value 的结构,
        //或者需要字符串以外的值做键,使用Map更合适

        // // 只有模拟现实世界的实体时,才使用对象
        // const person = {}

12-5 Map的应用

// Map的应用
        // const [p1,p2,p3] =  document.querySelectorAll('p');

        // const m = new Map();
        // m.set(p1,'red');
        // m.set(p2,'green');
        // m.set(p3,'blue');

        // const m = new Map([
        //     [p1,{
        //         color:'red',
        //         backgroundColor:'yellow',
        //         fontSize:'40px'
        //     }],
        //     [p2,{
        //         color:'green',
        //         backgroundColor:'pink',
        //         fontSize:'40px'
        //     }],
        //     [p3,{
        //         color:'blue',
        //         backgroundColor:'orange',
        //         fontSize:'40px'
        //     }]
        // ])

        // m.forEach((propObj,elem) => {
        //     for(const p in propObj) {
        //         elem.style[p] = propObj[p];
        //     }
        // })

        // console.log(m);
        
        
        //使用map方法
        const m1 = new Map([
            ['color','red'],
            ['backgroundColor','yellow'],
            ['fontSize','40px']
        ])

        const m2 = new Map([
            ['color','green'],
            ['backgroundColor','pink'],
            ['fontSize','40px']
        ])

        const m3 = new Map([
            ['color','blue'],
            ['backgroundColor','orange'],
            ['fontSize','40px']
        ])

        const m = new Map([
            [p1,m1],
            [p2,m2],
            [p3,m3]
        ])

        console.log(m);

        m.forEach((map,elem) => {
            map.forEach((propObj,prop) => {
                elem.style[prop] = propObj
                // elem.style.color = propObj
                // console.log(prop,propObj);
            })
        })

十三 遍历

13-1 Iterator是什么

//1. Iterator的作用
        // Iterator: 遍历器(迭代器)
        // for()
        // [1,2].forEach
        // new Set().forEach

        //Iterator 也是用来遍历的

        //2.寻找 Iterator
        // console.log(Iterator);

        // console.log([1,2][Symbol.iterator]());


        // //3.使用Iterator
        // const it = [1,2][Symbol.iterator]();
        // console.log(it.next()); //{value: 1, done: false}
        // console.log(it.next()); //{value: 1, done: false}
        // console.log(it.next()); //{value: undefined, done: true}

        //it: 可遍历对象 (可迭代对象)
        //Symbol.iterator:可遍历对象的生成方法

        //4.什么是Iterator
        //Symbol.iterator (可遍历对象的生成方法) -> it (可遍历对象) -> it.next() -> ...(直到done为true)

13-2 Iterator解惑

 // 1.为什么需要Iterator遍历器
        // 遍历数组:for循环和forEach方法
        // 遍历对象:for in 循环

        // Iterator遍历器是一个统一的遍历方式

        // console.log([][Symbol.iterator]());

        // console.log({}[Symbol.iterator]);


        // 2. 如何更方便的使用Iterator
        // Symbol.Iterator -> it -> next();

        // 我们一般不会直接使用Iterator去遍历

13-3 for...of的用法1

// 1. 认识for...of
        // const arr = [1,2,3];
        // const it = arr[Symbol.iterator]();
        // // console.log(it.next());
        // // console.log(it.next());
        // // console.log(it.next());
        // // console.log(it.next());

        // // let next =  it.next();
        // // console.log(next);
        // // while(!next.done) {
        // //     console.log(next.value);
        // //     next =  it.next();
        // // }

        // for(const item of arr) {
        //     console.log(item);
        // }
        //for...of循环只会遍历出那些done为false时,对应的value值

13-3 for...of的用法2

//2.与break、continue一起使用
        // const arr = [1,2,3];
        // for(const item of arr) {
        //     if(item === 2) {
        //         // break;
        //         continue;
        //     }
        //     console.log(item);
        // }

        // 3.在for...of中取得数组的索引
        // const arr = [1,2,3];
        // console.log(arr.keys());
        // for(const key of arr.keys()) {
        //     console.log(key);
        // }


        //values()得到的是值的可遍历对象,可以遍历出值
        // for(const value of arr.values()) {
        //     console.log(value);
        // }

        // entries()得到的是索引+值组成的数组的可遍历对象
        // for(const entries of arr.entries()) {
        //     console.log(entries);
        // }

13-5 原生可遍历与非原生可遍历

// 1. 什么是可遍历
        // 只要有Symbol.iterator方法,并且这个方法可以生成可遍历对象,就是可遍历的

        // 只要可遍历,就可以使用for...of循环来统一遍历

        // 2.原生可遍历的有哪些
        // 数组
        // 字符串
        // Set
        // Map
        // arguments
        // NodeList

        // for(const item of new Set([1,2,3])) {
        //     console.log(item);
        // }

        // 3.非原生可遍历的有哪些
        // 一般的对象
        // const person = {sex:'male',age:18};
        // console.log(person[Symbol.iterator]()); 
        
        // person[Symbol.iterator] = () => {
        //     let index = 0;
        //     return {
        //         next(){
        //             index++;
        //             if(index === 1) {
        //                 return {
        //                     value:person.age,
        //                     done:false
        //                 };
        //             } else if(index === 2) {
        //                 return {
        //                     value:person.sex,
        //                     done:false
        //                 }
        //             } else {
        //                 return {
        //                     done:true
        //                 }
        //             }
        //         }
        //     }
        // }

        // for (const item of person) {
        //     console.log(item);
        // }

        // 有length和索引属性的对象
        // const obj = {
        //     0:'alex',
        //     1:'male',
        //     length:2
        // };


        // obj[Symbol.iterator] = Array.prototype[Symbol.iterator]

        // obj[Symbol.iterator] = () => {
        //     let index = 0;

        //     return {
        //         next() {
        //             let value,done;
        //             if(index <obj.length) {
        //                 value = obj[index];
        //                 done = false;
        //             } else {
        //                 value = undefined;
        //                 done = true;
        //             }

        //             index++;

        //             return {
        //                 value,
        //                 done
        //             };
        //         }
        //     };
        // };

        // for(const item of obj) {
        //     console.log(item);
        // }

13-6 使用Iterator的场合

// 原生可遍历的
        // Array数组
        // String字符串
        // Set
        // Map
        // 函数的arguments对象
        // NodeList对象

        // for...of

        //1. 数组的展开运算符
        // console.log(...[1,2,3]);

        // console.log(...'str');
        //  console.log({...{}});


        // //2. 数组的解构赋值
        // [a,b] = [1,2,3];
        // [a,b] = 'h1';


        //3.Set和Map的构造函数
        // new Set(ierator);
        // new Map(iterator)

十四 字符串的新增方法

14-1 includes()

//1.基本用法
        // console.log('abc'.includes('ab'));
        // console.log('abc'.includes('ac')); //false

        // //2. 第二个参数
        // // 表示开始搜索的位置,默认是0
        // console.log('abc',includes('a'));
        // console.log('abc',includes('a',0));
        // console.log('abc',includes('a',1)); //false

        //3.应用
        // https://www.imooc.com/course/list

        // let url = 'https://www.imooc.com/course/list';
        // const addURLParam = (url,name,value) => {
        //     url += url.includes('?') ? '&' : '?';

        //     url += `${name}=${value}`;
            
        //     return url;
        // }
        // url = addURLParam(url,'c','fe');
        // console.log(url);

14-2 padStart()和padEnd()

//补全字符串长度
        
        //1. 基本用法
        // console.log('x'.padStart(5,'ab'));
        // console.log('x'.padEnd(5,'ab'));
        // console.log('x'.padEnd(4,'ab'));

        //2. 注意事项
        // 原字符串的长度,等于或大于最大长度,不会消减原字符串,字符串补全不生效,返回原字符串
        // console.log(('xxx'.padStart(10,'011')));

        // console.log('abc'.padEnd(10,'0123456789'));
        
        //如果省略第二个参数,默认使用空格补全长度
        // console.log('x'.padStart(4));
        // console.log('x'.padEnd(4));


        //3. 应用
        // 显示日期格式

        // console.log('1'.padStart(2,0));

14-3 trimStart()和trimEnd()

 //清除字符串的首尾空格,中间的空格不会清除

        // 1.基本用法
        // const s = ' a b c ';
        // console.log(s);
        // console.log(s.trimStart());
        // console.log(s.trimEnd());
        // console.log(s.trimLeft());
        // console.log(s.trimRight());
        // console.log(s.trim());

        //2.应用
        // const usernameInput = document.getElementById('username');
        // const btn = document.getElementById('btn');

        // btn.addEventListener(
        //     'click',
        //     () => {
        //         console.log(usernameInput.value);


        //         //验证
        //         if(usernameInput.value.trim() !== '') {
        //             //可以提交
        //             console.log('可以提交');
        //         } else {
        //             //不能提交
        //             console.log('不能提交');
        //         }
        //         //手动提交
        //     },
        //     false
            
        // )

十五 数组的新增方法

15-1 includes()

// 判断数组找那个是否含有某个成员的


        //基本遵循严格相等( === ),但是对于NaN的判断与 === 不同,
        // includes 认为NaN === NaN
        // console.log([1,2,NaN].includes(NaN));

        // console.log([1,2,3].includes(2));
        // console.log([1,2,3].includes('2'));
        
        // 第二个参数表示搜索的起始位置,默认值是0
        // console.log([1,2,3].includes(2,2));

        // 2.应用
        // 去重
        // [1,2,1];

        // const arr = [];
        // for(const item of [1,2,1]) {
        //     if(!arr.includes(item)) {
        //         arr.push(item)
        //     }
        // }
        // console.log(arr);

15-2 Array.from()

//将其他数据类型转成数组

        //1.基本用法
        // console.log(Array.from('str'));

        //2. 哪些可以通过Array.from()转换成数组
        //2.1 所有可遍历的
        // 数组、字符串、set、map、nodeList、arguments
        // console.log(Array.from(new Set([1,2,1])));

        // console.log([...new Set([1,2,1])]);

        //2.2 拥有length 属性的任意对象
    //     const obj = {
    //         length:3,
    //         '0':'a',
    //         '1':'b',
    //         name:'Alex',

    //     };
    //     console.log(Array.from(obj));

    //3.第二个参数
    //作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组
    // console.log(    
    //     [1,2].map((value) => {
    //         return value*2
    //     }
    // ));

    // console.log(Array.from('12',value => value * 2));
    // console.log(Array.from('12').map(value => value*2));

    // //4.第三个参数
    // Array.from(
    //     '12',
    //     function () {
    //         console.log(this);
    //     },
    //     document
    // )

15-3 find()和findIndex()

//find(): 找到满足条件的一个立即返回
    //findIndex(): 找到满足条件的一个,立即返回索引

    //1.基本用法
    // console.log(
    //     [1,5,10,15].find((value,index,arr) => {
    //         // console.log(value,index,arr);
    //         return value>9
    //     })
    // );

    // console.log(
    //     [1,5,10,15].findIndex((value,index,arr) => {
    //         // console.log(value,index,arr);
    //         return value>9
    //     })
    // );


    //2. 应用
    // const students = [
    //     {
    //         name:'张三',
    //         sex:'男',
    //         age:16
    //     },        
    //     {
    //         name:'李四',
    //         sex:'女',
    //         age:22
    //     },
    //     {
    //         name:'王二麻子',
    //         sex:'男',
    //         age:32
    //     },
    // ];
    // console.log(students.find(value => value.sex === '女'));
    // console.log(students.findIndex(value => value.sex === '女'));

对象的新增方法

16-1 Object.assign();

// 用来合并对象

    //1.基本用法
    // Object.assign(目标对象,源对象1,...)

    // const apple = {
    //     color:'红色',
    //     shape:'圆形',
    //     taste:'甜'
    // };
    // const pen = {
    //     color:'黑色',
    //     shape:'圆柱形',
    //     use:'写字'
    // }

    //Object.assign 直接河滨到了第一个参数中,返回的就是合并后的对象

    //可以合并多个对象
    // console.log(Object.assign(apple,pen));
    // console.log(apple,apple === Object.assign(apple,pen));
    // console.log(Object.assign({},apple,pen));
    // console.log({...apple,...pen});

    //2.注意事项
    //2.1 基本数据类型作为源对象
    // 与对象的展开类似,先转换成对象,再合并
    // console.log(Object.assign({},undefined));
    // console.log(Object.assign({},null));
    // console.log(Object.assign({},1));
    // console.log(Object.assign({},true));
    // console.log(Object.assign({},'str'));


    //2.2同名属性的替换
    //后面的直接覆盖前面的
    // const apple = {
    //     color:['红色','黄色'],
    //     shape:'圆形',
    //     taste:'甜'
    // };
    // const pen = {
    //     color:'黑色',
    //     shape:'圆柱形',
    //     use:'写字'
    // };
    // console.log(Object.assign({},apple,pen));

    

    // 3.应用
    //合并默认参数和用户参数
    // const logUser = userOptions=> {
    //     const DEFAULTS={
    //         username:'ZhangSan',
    //         age:0,
    //         sex:'male'
    //     };

    //     const options = Object.assign({},DEFAULTS,userOptions);
    //     console.log(options);
    // }
    // //logUser
    // logUser()

16-2 Object.keys()、Object.values()、Object.entries()

 //1. 基本用法
    // const person = {
    //     name:'Alex',
    //     age:18
    // }

    // console.log(Object.keys(person));
    // console.log(Object.values(person));
    // console.log(Object.entries(person));

    // //2. 与数组类似方法的区别
    // console.log([1,2].keys());
    // console.log([1,2].values());
    // console.log([1,2].entries());

    //数组的keys()、values()、entries()等方法是实例方法,返回的都是Iterator
    //对象的Object.keys()、Object.values()、Object.entries
    //()等方法时构造函数方法、返回的是数组

    //3. 使用for...of循环遍历对象
    // const person = {
    //     name:'Alex',
    //     age:18
    // };
    // for(const key of Object.keys(person)) {
    //     console.log(key);
    // }

    // for(const value of Object.values(person)) {
    //     console.log(value);
    // }

    // for(const entries of Object.entries(person)) {
    //     console.log(entries);
    // }

    //Object.keys()/valuess()/entires()并不能保证顺序一定是你看到的样子,
    //这一点和for in 是一样的

十七 初始Promise

17-1 Promise是什么

//1. 认识Promise
    // Promise是异步操作的一种解决方案
    // 回调函数
    // document.addEventListener(
    //     'click',
    //     () => {
    //         console.log('这里是异步的');
    //     },
    //     false
    // );
    //     console.log('这里是同步的');

    
    //2. 什么时候使用Promise
    // Promise一般用来解决层层嵌套的回调函数(回调低于 callback hell)的问题

17-2 Promise的状态

//1. 实例化构造函数生成实例对象
    // console.log(Promise);

    //Promise解决的不是回调函数,而是回调地狱
    // const p =  new Promise(() => {});

    //2. Promise的状态
    // const p = new Promise((resolve,reject) => {
    //     //Promise有3种状态,一开始是pending(未完成),
    //     //执行resolve,变成fulfilled(resolved),已成功
    //     // resolve();



    //     //执行reject,变成rejected,已失败

    // Promise的状态一旦变化,就不会再改变了

    //     //pending -> fulfilled
    //     resolve({username:'alex'});

    //     //pending -> rejected
    //     reject();
    // })


    // //3.then 方法
    // p.then(data =>{
    //     console.log('success',data);
    // },
    // ()=> {
    //     console.log('error');
    // })
    // console.log(p);

十八 实例方法

18-1 then()

//1.什么时候执行
    //pending -> fulfilled时,执行then的第一个回调函数
    //pending -> rejected时,执行then的第二个回调函数

    //2.执行后的返回值
    //then方法执行后返回一个新的Promise对象
    // const p = new Promise((resolve,reject) => {
    //     resolve();
    // });
    // const p2 = p.then(
    //     () => {},
    //     () => {}
    // )
    // .then()
    // .then()

    //console.log(p,p2,p === p2);

    //3.then方法返回的Promise对象的状态改变
    // const p = new Promise((resolve,reject) => {
    //     // resolve();
    //     reject()
    // });
    // p.then(
    //     () => {
    //         console.log('success');
    //     },
    //     () => {
    //         console.log('err');

    //         // 在then的回调函数中,return后面的东西,会用Promise包装一下
    //         // return undefined;
    //         //等价于
    //         // return new Promise((resolve,reject) => {
    //             // resolve(123);
    //         // })
            
    //         // 默认返回的永远都是成功状态的Promise对象
    //         return new Promise((resolve,reject) => {
    //             reject('reason')
    //         })
    //     }
    // )
    // .then(
    //     () => {
    //         console.log('success2');
    //     },
    //     (err) => {
    //         console.log('err2',err);
    //     }
    // )

18-2 Promise解决回调地狱

 <div id="box"></div>
    <script>
        const move = (el,{x = 0,y = 0} ={},end = ()=>{}) => {
            el.style.transform = `translate3d(${x}px,${y}px,0)`
            el.addEventListener(
                'transitionend',
                () => {
                    end();
                },
                false
            )
        }
        const movePromise = (el,point) => {
                return new Promise(resolve => {
                    move(el,point,() => {
                        resolve();
                    })
                })
            }

        const boxEI = document.getElementById('box');

        // document.addEventListener(
        //     'click',
        //     () => {
        //         move(boxEI,{x:150},() => {
        //             move(boxEI,{x:150,y:150},()=> {
        //                 move(boxEI,{y:150},()=> {
        //                     move(boxEI,{x:0,y:0})
        //                 })
        //             })
        //         })
        //     }
        // )


        document.addEventListener(
            'click',
            () => {
            movePromise(boxEI,{x:150}).then(() => {
                return movePromise(boxEI,{x:150,y:150})
            }).then(() => {
                return movePromise(boxEI,{y:150});
            }).then(() => {
                return movePromise(boxEI,{x:0,y:0})
            })
        },
        false
        )
    </script>

18-3 catch()

<script>
        // 1.有什么用
        // then(
        //     data => {},
        //     ett => {}
        // )
        // then(data => {});

        //catch专门用来处理reject状态
        //catch本质上是then的特例
        // then(null,err=>{});

        //2. 基本用法
        new Promise ((resolve,reject) => {
            // resolve(123)
            reject('reason');
        })
        // .then(data => {
        //     console.log(data);
        // })
        // .then(null,err=> {
        //     console.log(err);
        // })
        .catch(err => {
            console.log(err);

            //return undefined
        }).then(data => {
            console.log(data);
        });

        //catch()可以捕获它前面的错误
        //一般总是建议,Promise对象后面要跟catch方法,这样可以处理
        //Promise内部发生的错误

        
    </script>

十九 构造函数方法

19-1 Promise,resolve()和Promise.reject()

<script>
        // 1.Promise.resolve()
        // 是成功状态Promise的一种简写形式
        // new Promise(resolve => resolve('foo'))
        //简写
        //Promise.resolve('foo')

        
        //参数
        //一般参数
        // Promise.resolve('foo').then(data=>{
        //     console.log(data);
        // });


        //Promise
        //当Promise.resolve()接收的是Promise对象时,直接返回这个Promise对象,什么都不做
        // const p1 = new Promise(resolve => {
        //     setTimeout(resolve,1000,'我被执行了');
        //     // setTimeout(()=> {
        //     //     resolve('我被执行了')
        //     // },1000)
        // })
        // Promise.resolve(p1).then(data => {
        //     console.log(data);
        // })
        // //等价于
        // p1.then(data => {
        //     console.log(data);
        // });
        // console.log(Promise.resolve(p1) === p1);
        


        //当resolve函数接收的是Promise对象时,后面的then会根据传递的Promise对象的状态变化决定执行哪一个回调
        // new Promise(resolve => resolve(p1)).then(data => {
        //     console.log(data);
        // });


        // 具有then方法的对象
        // const thenable = {
        //     then(resolve,reject) {
        //         console.log('then');
        //         resolve('data');
        //         // reject('reason')
        //     }
        // }
        // Promise.resolve(thenable).then(
        //     data => console.log(data),
        //     err => console.log(err)
        // );


        //2. Promise.reject()
        //失败状态Promise的一种简写形式
        // new Promise((resolve,reject) => {
        //     reject('reason')
        // });
        //等价于
        //Promise.reject('reason');

        //参数
        //不管什么参数,都会原封不动地向后传递,作为后续方法的参数
        // const p1 = new Promise(resolve => {
        //     setTimeout(resolve,1000,'我被执行了');
        // })
        // Promise.reject(p1).catch(err => {
        //     console.log(err);
        // })

        new Promise((resolve,reject) => {
            resolve(123)
        })
        .then(data => {
            console.log(data);
        })
        .then(data => {
            console.log(data);
        })
        .catch(err => console.log(err))
</script>

19-2 Promise.all()

 <script>
        //1. 有什么用
        //Promise.all()关注多个Promise对象的状态变化
        //传入多个Promise实例,包装成一个新的Promise实例返回

        //2. 基本用法
        const delay = ms => {
            return new Promise(resolve => {
                setTimeout(resolve,ms)
            })
        }

        const p1 = delay(1000).then(() => {
            console.log('p1 完成了');

            // return 'p1'
            return Promise.reject('reason')
        });

        const p2 = delay(2000).then(() => {
            console.log('p2 完成了');

            return 'p2'
        })



        //Promise.all()的状态变化与所有传入的Promise实例对象状态有关
        //所有状态都编程resolved,最终的状态才会变成resolved
        //只要有一个变成rejected,最终的状态就变成rejected

        const p = Promise.all([p1,p2]);
        p.then(data => {
                console.log(data);
            },
            err => {
                console.log(err);
            }
        )
    </script>

19-3 Promise.race()和 Promise.allSettled()

    <script>
        //1.Promise.race()
        const delay = ms => {
            return new Promise(resolve => {
                setTimeout(resolve,ms)
            })
        }

        const p1 = delay(1000).then(() => {
            console.log('p1 完成了');

            return 'p1'
            // return Promise.reject('reason')
        });

        const p2 = delay(2000).then(() => {
            console.log('p2 完成了');

            return 'p2'
        })


        //Promise.race()的状态取决于第一个完成的Promise实例对象,
        //如果第一个完成的成功了,那最终的就成功;如果第一个完成的失败了,那最终的就失败
        // const racePromise = Promise.race([p1,p2]);
        // racePromise.then(
        //     data => {
        //         console.log(data);
        //     },
        //     err => {
        //         console.log(err);
        //     }
        // )

        //2.Promise.allSettled()
        //Promise.allSettled()的状态与传入的Promise状态无关
        //永远都是成功的
        //它只会忠实的记录下各个Promise的表现
        const allSettledPromise = Promise.allSettled([p1,p2]);
        allSettledPromise.then(
            data => {
                console.log('succ',data);
            },
            err => {
                console.log(err);
            }
        )
    </script>

二十 注意事项和应用

20-1 Promise的注意事项

    <script>
        //1.resolve或reject函数执行后的代码
        new Promise((resolve,reject) => {
            // reject('reason');
            // console.log('hi');
        })

        //2.Promise.all/race/allSettled的参数问题
        //参数如果不是Promise数组,会将不是Promise的数组元素转变成Promise对象
        //Promise.all([1,2,3]).then(datas => {
        //     console.log(datas);
        //})
        // 等价于
        // Promise.all([
        //     Promise.resolve(1),
        //     Promise.resolve(2),
        //     Promise.resolve(3)
        // ]).then(datas => {
        //     console.log(datas);
        // })


        //不只是数组,任何可遍历的都可以作为参数
        //数组、字符串、Set、Map、NodeList、arguments
        // Promise.all(new Set([1,2,3])).then(datas => {
        //     console.log(datas);
        // })

        //3.Promise.all/race/allSettled的错误处理

        const delay = ms => {
            return new Promise(resolve => {
                setTimeout(resolve,ms)
            })
        }

        const p1 = delay(1000).then(() => {
            console.log('p1 完成了');

            // return 'p1'
            return Promise.reject('reason')
        })
        .catch(err => {
            console.log('p1',err);
        })

        const p2 = delay(2000).then(() => {
            console.log('p2 完成了');

            return 'p2'
        })

        const allPromise = Promise.all([p1,p2]);
        allPromise.then(datas => {
            console.log(datas);
        }).catch(err => {
            console.log(err);
        })

        //错误既可以单独处理,也可以统一处理
        //一旦被处理,就不会在其他地方再处理一遍
    </script>

20-2 Promise的应用

   <img src="https://img.mukewang.com/5e6af63d00011da31872076.jpg" alt="图片返回异常" id="img">
    <script>
        //1. 异步加载图片

        const loadImgAsync = url =>{
            return new Promise((resolve,reject)=> {
                const img = new Image();

                img.onload = ()=> {
                    resolve(img)
                };

                img.onerror = () => {
                    reject(new Error(`Could not load image at ${url}`))
                }

                img.src = url;
            })
        }
        const imgDOM = document.getElementById('img')
        loadImgAsync('https://img.mukewang.com/5f057a6a0001f4f918720764.jpg').then(
            img => {
                console.log(img.src);
                setTimeout (() => {
                    imgDOM.src = img.src
                },1000)
            }
        ).catch(err => {
            console.log(err);
        }
              
        )
    </script>

二十一 初识Class

21-1 Class是什么

    <script>
        // 1.认识Class
        // 人类:类
        // 具体的人:实例、对象


        //类可以看做是对象的模板,用一个类可以创建出许多不同的对象

        //2.Class的基本用法
        // 类名一般首字母大写
        // class Person {} {} x
        class Person {
            //实例化时执行构造方法,所有必须有构造方法,但可以不写出来
            construtor(name,age) {
                this.name = name;
                this.age = age

                //一般在构造方法中定义属性,方法不在构造方法中定义
                // this.speak = ()=>{};
            }

            //各实例共享的方法
            speak(){
                console.log('speak');
            }
        }

        // Person()
        const p = new Person('ZS',18);
        p.speak()
    </script>

21-2 Class的两种定义方式

 <script>
        //1. 声明形式
        // class Person {
        //     constructor() {}
        //     speak(){}
        // }

        //2.表达式形式
        // function Person(){}
        // const Person = function () {};

        const Person = class {
            constructor() {
                console.log('construtor');
            }

            speak() {
                
            };
        }
        new Person();

        (function () {
            console.log('func');
        })()


        //立即执行的类
        new (class {
            constructor() {
                console.log('construtor');
            }
        })()
    </script>

二十二 属性与方法

22-1 实例属性、静态方法、静态属性

<script>
        //1. 实例属性
        // class Person { 
        //     age = 18 
        //     sex = 'male'
        //     getSex = function () {
        //         return this.sex;
        //     }

        //     constructor (name,sex) {
        //         this.name = name;
        //         this.sex = sex;
        //     }
        // }

        // const p = new Person('Alex');
        // console.log(p.name);


        //2.静态方法
        //类的方法

        // class Person { 
        //     constructor (name,sex) {
        //         this.name = name;
        //         this.sex = sex;
        //     }

        //     speak() {
        //         console.log('speak');
        //         console.log(this);
        //     }

        //     static speak() {
        //         console.log('static speak');

        //         //this指向类
        //         console.log(this);
        //     }
        // }

        // const p = new Person('Alex');

        // p.speak();

        // Person.speak();

        

        //3. 静态属性
        // 类的属性
        class Person { 
            constructor (name) {
                this.name = name;
            }

            //不要这么写,目前只是题案,有兼容性问题
            // static version='1.0' 

            static getVersion() {
                return '1.0'
            }
        }

        // Person.version = '1.0'

        const p = new Person('Alex');
        console.log(p.name);

        // console.log(Person.version);
        console.log(Person.getVersion());


    </script>

22-2 私有属性和方法

 <script>
        //1.为什么需要私有属性和方法
        //一般情况下,类的属性和方法都是公开的
        //公有的属性和方法可以被外界修改,造成意想不到的错误
        // class Person {
        //     constructor (name) {
        //         this.name = name;
        //     }

        //     speak() {
        //         console.log('speak');
        //     }

        //     getName() {
        //         return this.name;
        //     }
        // }

        // const p = new Person('Alex');
        // console.log(p.name);
        // p.speak();

        //...
        // p.name = 'zs';


        //2.模拟私有属性和方法
        //2-1._开头表示私有

        // class Person {
        //     constructor (name) {
        //         this._name = name;
        //     }

        //     speak() {
        //         console.log('speak');
        //     }

        //     getName() {
        //         return this._name;
        //     }
        // }

        // const p = new Person('Alex');
        // console.log(p.name);
        // console.log(p.getName());

        //2.2 将私有属性和方法移出类

        (function() {
            let name = ''

            class Person {
                constructor (username) {
                    name = username;
                }

                
                getName() {
                    return name
                }
            }

            window.Person = Person;
        })();

        (function () {
            const p = new Person('Alex');
            console.log(p.getName());
        })();

    </script>

二十三 继承

23-1 extends

    <script>
        //1. 子类继承父类
        class Person {
            constructor(name,sex) {
                this.name = name;
                this.sex = sex;

                this.say = function () {
                    console.log('say');
                }
            }

            static speak () {
                console.log('static speak');
            }
        }
        // Person.version = '1.0';

        // class Programmer extends Person {
        //     constructor(name,sex){
        //         super(name,sex)

        //     }
        // }

        // const zs =  new Programmer('zs','男')
        // console.log(zs.name);
        // console.log(zs.sex);
        // zs.say();
        // Programmer.speak();


        //2.改写继承的属性或方法

        class Programmer extends Person {
            constructor(name,sex,feature){
                super(name,sex)

                this.feature = feature
            }

            //同名覆盖
            speak() {
                console.log('Programmer speak');
            }

            static speak() {
                console.log('Programmer static speak');
            }
        }

        const zs =  new Programmer('zs','男','秃头')
        console.log(zs.name);
        console.log(zs.feature);
        zs.say();
        Programmer.speak();
    </script>

23-2 super

<script>
        //1.作为函数调用
        //代表父类的构造方法,只能在子类的构造方法中,用在其他地方就会报错

        //super虽然代表了父类的构造方法,但是内部的this指向子类的实例
        // class Person {
        //     constructor(name) {
        //         this.name = name;

        //         console.log(this);
        //     }
        // }
        // class Programmer extends Person {
        //     constructor(name,sex) {
        //         super(name,sex);
        //     }
        // }

        // // new Person();
        // new Programmer();


        //2.作为对象使用
        //2.1 作为构造方法使用或一般方法中使用
        // super代表父类的原型对象 Person.prototype
        // 所以定义在父类实例上的方法或属性,是无法通过super调用的
        //通过super调用父类的方法时,方法内部的this指向当前的子类实例
        // class Person {
        //     constructor(name) {
        //         this.name = name;

        //         console.log(this);
        //     }

        //     speak() {
        //         console.log('speak');
        //         console.log(this);
        //     }

        //     static speak() {
        //         console.log('static speak');
        //         console.log(this);
        //     }
        // }

        // class Programmer extends Person {
        //     constructor(name,sex) {
        //         super(name,sex);

        //         // console.log(super.name);
        //         // super.speak()
        //     }

        //     speak() {
        //         super.speak();
        //         console.log(('Programmer speak'));
        //     }


        //     //2.2 在静态方法中使用
        //     // 指向父类,而不是父类的原型对象
        //     // 通过super调用父类的方法时,方法内部的this指向当前的子类,而不是子类的实例
        //     static speak() {
        //         super.speak();
        //         console.log('Programmer speak');
        //     }

        // }

        // // new Person()
        // // new Programmer()
        // Programmer.speak()


        //3.注意事项
        // 使用super的时候,必须显式指定是作为函数还是作为对象使用,否则会报错

        class Person {
            constructor(name) {
                this.name = name;
            }

            speak() {
                console.log('speak');
                console.log(this);
            }
        }

        class Programmer extends Person {
            constructor(name,sex) {
                super(name,sex);

                // console.log(super);
                console.log(super.speak);
                console.log(super());
            }

        }
        
    </script>

二十五、 初识Module

25-1 Module是什么

1. 什么是模块


模块:一个一个的局部作用域的代码块

2. 什么是模块系统


模块系统需要解决的主要问题

  • ①模块化的问题
  • ②消除全局变量
  • ③管理加载顺序


RequireJS seaJS


ES Module

25-2 Module的基本用法

1. 使用Module模块化之前的例子

2. 使用script标签加载模块

一个文件就是一个模块
只要你会用到import或export,在使用script标签加载的时候,就要加上type='module'

3. 分析Module解决问题

二十六、导入与导出

26-1 Module的两种导出和导入

1. 认识导出和导入

导出的东西可以被导入(import),并访问到


一个模块没有导出,也可以将其导入
被导入的代码都会执行一遍,也仅会执行一遍
import './js模块/module.js'

2. 基本用法

可以随便起名

import age from './js模块/module.js';
console.log(age);

一个模块只能有一个export default

image.png

26-2 export和对应的import

// js模块部分

image.png

html部分

image.png

二十七、注意事项与应用

27-1 Module的注意事项

js模块部分

image.png
html部分

image.png

二十八、Babel

28-1 Babel是什么

1. 认识Babel

官网:babeljs.io/
在线编译:babeljs.io/repl


Babel 是JavaScript的编译器,用来将es6的代码,转换成es6之前的代码

2. 使用Babel

Babel本身可以编译ES6的大部分语法,比如let、const、箭头函数、类
但是对于ES6新增的API,比如Set、Map、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign/Array.from)都不能直接编译,需要借助其他的模块
Babel一般需要配合Webpack来编译模块语法

28-3 使用Babel前的准备工作

1. 什么是Node.js 和 npm

Node.js是个平台或者工具,对应浏览器
后端的JavaScript = ECMAscript + IO + File + ...等服务器端的操作


npm: node包管理工具

2. 安装Node.js

node -v npm -v

3.初始化项目

npm init -> package.json

4. 安装Babel需要的包

npm config set registry registry.npm.taobao.org


npm install --save-dev @babel/core @babel/cli


npm install (如果不写包名会自动找同文件的package文件下载里面记录的)

28-4 使用Babel编译ES6代码

babeljs.io/setup

1. 执行编译的命令

在package.json 文件中添加执行babel的命令
babel src -d dist
babel src --out-dir dist

2. Babel的配置文件

.babelrc


npm install @babel/preset-env@7.11.0 --save-dev


创建配置文件 .babelrc,并配置

{
    "presets":["@babel/preset-env"]
}

二十九 Webpack入门

29-1 Webpack是什么

1. 认识Webpack

webpack是静态模块打包器,当webpack处理应用程序时,会将所有这些模块打包成一个或多个文件
//import'./module.js'
//require('./module.js')

2. 什么是Webpack

模块
webpack可以处理js/css/图片、图标字体等单位


静态
开发过程中存在于本地的js/css/图片/图标字体等文件,就是静态的
动态的内容,webpack没办法处理,只能处理静态的

29-2 Webpack初体验

1. 初始化项目

npm init

2. 安装Webpack需要的包

npm install --save-dev webpack-cli@3.3.12 webpack@4.44.1

3. 配置Webpack

webpack.config.js

4.编译并测试

三十 Webpack的核心概念

30-1 Webpack的4个核心理念

entry和output
image.png

30-2 loader

1.什么是loader

webpack js/css/图片


loader 让Webpack能够去处理那些非JS文件的模块

babel

2. babel-loader

npm install --save-dev babel-loader@8.1.0 @babel/core@7.11.0 @babel/preset-env@7.11.0

image.png