JS高级笔记

106 阅读7分钟

01 js高级-数组的方法-面向对象

箭头函数

公式: const func2 = () => { }

相对以前的function() {} 会更加方便 简易

箭头函数-代码示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
    />
    <title>02-箭头函数.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <button>点击我</button>
    <script>
      // 以前写函数
      function func1(num1) {
        return num1 + 100;
      }

      // 箭头函数的时候
      // const func2 = (num1) => num1 + 100;

      // 定义一个箭头函数 没有形参 没有返回值
      const func2 = () => {
        console.log('执行业务1');
        console.log('执行业务2');
      };

      // 没有形参、没有返回值、业务只有一行代码 大括号都可以省略
      const func3 = () => console.log('执行业务1');

      // 只有一个形参、没有返回值、业务只有一行代码
      // const func4 = num => console.log(num + 1);
      // const func4 = (num) => console.log(num + 1);

      // 两个或者多个参数(括号不能省略)、没有返回值、业务只有一行代码
      // const func5 = (a, b) => console.log(a + b);

      // 没有形参,有返回值 业务两行代码
      const func6 = () => {
        let a = 100;
        return a + 100;
      };

      // 没有形参、有返回值,业务一行代码
      // const func7 = () => {
      //   return 100 + 200;
      // };
      // 没有形参、有返回值,业务一行代码 等价上述写法
      const func7 = () => 100 + 200; // 相等于 return 100+200

      console.log(func7());

      const button = document.querySelector('button');
      button.addEventListener('click', () => {
        console.log(123321);
      });

    </script>
  </body>
</html>

箭头函数-返回对象

如果你一定要在箭头函数中想要通过省略 return 的方式来返回对象,请你加上一个小括号

const func7 = (num) => ( {a:123} );

如果不加小括号 那么就会返回 unfinished

const func8=(num)=>{a:123}; unfinished

代码示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
    />
    <title>05-箭头函数-返回对象.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <script>
      const arr = ['a', 'b', 'c'];
      // 返回 [  {name:"a",name:"b",name:"c"} ]

      // 如果你一定要在箭头函数中想要通过省略 return的方式来 返回对象,请你加上一个小括号
      const func7=(num)=>({a:123});// => 右边加了小括号 表示想要返回 小括号里面的数据 return {a:123};
      const func8=(num)=>{a:123};// => undefined

      console.log(func7()); {a:123}
      console.log(func8());// undefined
    </script>
  </body>
</html>

数组方法-forEach()

遍历数组

forEach() 数组每一个元素都执行一次回调函数,类似以前的for 循环 forEach高阶函数(可以接收一个形参 - 函数)

公式:

const arr = ['a','b','c']

arr.forEach(value => console.log(值是${value})) 打印结果: 值是'a' 值是'b' 值是'c'

注意

for循环可以通过break来打断, forEach不能通过break来打断

代码 示例

        // forEach()	数组每个元素都执行一次回调函数。    = 类似以前的for   forEach 高阶函数(可以接收一个形参-函数)
        // for循环可以通过 break来打断、 forEach不能通过break打断
        const arr = ["a", "b", "c"];
        // 分别打印他们
        arr.forEach(function (value, index) {
          console.log(`值 是 ${value}  下标是 ${index}`);
        });

        arr.forEach((value, index) =>
          console.log(`值 是 ${value}  下标是 ${index}`)
        );

        arr.forEach((value) => console.log(`值 是 ${value}`));

数组方法-map()

map()根据原来得数组 来返回新的数组

也会循环数组 在循环的回调函数中可以返回新的数组 组装成新的数组

        // map 根据原来的数组 来返回新的数组
        // 也会循环数组 在循环的回调函数中可以返回新的数据 组装成新的数组
        // const arr = ['a', 'b', 'c'];
        // 可以返回 ["我的字母是a","我的字母是b","我的字母是c"]

        // const newArr = arr.map((value) => '我的字母是' + value); // [1,1,1]
        // console.log(newArr);

        // const list=[10,11,12];
        // const newList=list.map(value=>value+1);// [11,12,13]
        // console.log(newList);

        // const objectArr=[{name:"悟空"},{name:"八戒"}];
        // const newObjectArr=objectArr.map(value=>{
        //   // 1
        //   value.color="red";
        //   // 2
        //   return value
        // })// [{name:"悟空",color:"red"},{name:"八戒",color:"red"}]
        // console.log(newObjectArr);

        const texts = ["刘德华", "郭德纲", "林志颖"];
        // // 返回  [<div>刘德华</div>,<div>郭德纲</div>,<div>林志颖</div>]
        const newTexts = texts.map((value) => `<div>${value}</div>`);
        // console.log(newTexts);
        // // [<div>刘德华</div>,<div>郭德纲</div>,<div>林志颖</div>]
        // // 把它转成字符串
        const html = newTexts.join(""); // <div>刘德华</div><div>郭德纲</div><div>林志颖</div>
        // console.log(html);
        document.body.innerHTML = html;

        // 后面再说
        // const renderHTML=value=>`<div>${value}</div>`
        // document.body.innerHTML=["刘德华","郭德纲","林志颖"].map(renderHTML).join("");

捐赠管理-map()方法渲染-案例示例

<!DOCTYPE html>

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
    />
    <title>01-捐赠管理.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
      h3 {
        margin: 50px;
        text-align: center;
      }
      table {
        width: 800px;
        margin: 0 auto;
        border-collapse: collapse;
        text-align: center;
      }
      thead {
        background-color: #337ab7;
        color: #fff;
      }
      td,
      th {
        padding: 10px 50px;
        /* 设置文字不换行 */
        white-space: nowrap;
      }
    </style>
  </head>
  <body>
    <h3>捐赠管理</h3>
    <table border="1">
      <thead>
        <tr>
          <th>序号</th>
          <th>捐赠人</th>
          <th>收捐单位</th>
          <th>金额</th>
          <th>收捐日期</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody></tbody>
    </table>

    <script>
      // 获取tbody
      const tbody = document.querySelector("tbody");
      // 定义数据
      const arr = [
        // id:数据编号  person:捐赠人姓名   unit:捐赠单位名称  money:捐赠金额  date:捐赠日期
        {
          id: 1,
          person: "刘德化",
          unit: "壹基金",
          money: 1000,
          date: "2021-10-5",
        },
        {
          id: 2,
          person: "周杰伦",
          unit: "自然之友",
          money: 1000,
          date: "2021-01-15",
        },
        {
          id: 3,
          person: "李连杰",
          unit: "嫣然基金",
          money: 1000,
          date: "2021-06-7",
        },
      ];

      // 根据数组来渲染页面
      function render() {
        // 只能使用 map方法 和 数组转方式方法 join 来实现 拼接html的功能
        // 把 arr  转成(map、join 来实现功能) 变量 html 让下面的代码 (tbody.innerHTML = html;) 执行成功

        let newArr = arr.map(
          (value) => `
          <tr>
            <td>${value.id}</td>
            <td>${value.person}</td>
            <td>${value.unit}</td>
            <td>${value.money}</td>
            <td>${value.date}</td>
            <td>
      <a href="#" class="del">删</a>
      <a href="#" class="update">改</a>
              </td>
          </tr>

       `
        );
        let html = newArr.join("");
        tbody.innerHTML = html;
      }

      // 根据数组数组渲染页面
      render();
    </script>
  </body>
</html>

代办事项-filter方法过滤-案例示例


    // // 给每一个商品绑定点击事件
    for (let index = 0; index < checkboxList.length; index++) {
      checkboxList[index].addEventListener('click', function () {
        // 判断是否达到了全选 条件
        // 判断每一个小小的复选框的选中状态 如果都是true,那么就全选
        let checked = checkboxList.every((value) => {
          if (value.checked === true) {
            return true;
          } else {
            return false;
          }
        });
        // 设置全选按钮即可
        checkAll.checked = checked;
      });
    }
  </script>
</html>
<!-- 
  两个知识
  1 伪数组转真正的数组  let newArr=[...伪数组] ;
  2 every 要求数组的每一个元素都符号要求, every才返回true 
    使用场景, 商品全选 => 每一个小商品都选中, 全选才勾选!! 

  4 如果 数组 有every方法, list.every 看是不是undefined 
    不是的话 表示数组有 every方法 list.every() 调用
    是  表示数组没有 every方法,不用list.every() 
  
 -->

数组方法 - every()

进行判断 全部符合就会返回true 只要有一个不符合就返回false

      every();
      function every() {
        // 会返回 true或者false
        // 如果数组中每一个元素都复合条件,every返回true

        // const arr = [1, 6, 3, 4];
        // // 判断数组中每一个元素,是不是都小于 5 如果是  返回true

        // // every当中的函数,要求每一个都return 了true 最后 every的返回值才是true
        // const result = arr.every((value) => {
        //   if (value < 5) {
        //     return true;
        //   } else {
        //     return false;
        //   }
        // });
        // const result = arr.every((value) => value < 5);
        // console.log(result);

        // 有一个数组,存放每一个人 关于肺炎的检查结果
        const arr = [true, true, true, true, true]; // true就表示安全,false 中招
        // 我想要判断一下  这个人群安不安全  (只要有一个为false,不安全) 要求每一个都为true才安全

        // const result = arr.every((value) => {
        //   if (value === true) {
        //     return true;
        //   } else {
        //     return false;
        //   }
        // });
        // console.log(result);

        // every:
        //会返回true 或者 false
        //要求数组中每一个元素都符合条件,every 得到true
        //如果空数组调用了every  得到结果  也是true
      }

数组方法 -filter

过滤或者筛选

const arr = [1, 2, 3, 4, 5, 6, 7];

const newArr = arr.filter((value) => value % 2 !== 0);

过滤, 过滤出满足条件的数据 =>新的数组

        // 过滤, 过滤出满足条件的数据 =>新的数组
        const arr = [1, 2, 3, 4, 5, 6, 7];
        // 返回 奇数
        // const newArr = arr.filter((value) => {
        //   // 如果你return 了 true 表示当前的value你想要
        //   if (value % 2 !== 0) {
        //     // value  1 2 3 4 5 6
        //     // value%2!==0   value=[1,3,5,7]
        //     // 奇数
        //     return true;
        //   } else {
        //     return false;
        //   }
        // }); 简化
        const newArr = arr.filter((value) => value % 2 !== 0);
        console.log(newArr);
      }

数组方法-some()

检测数组,其中只要有一个元素符合条件,some返回true ( every要求每一个都符合 )

公式:

const arr = [1, 3, 4, 6, 7];

const result = arr.some((value) => value > 6); //true

        // 检测数组,其中只要有一个元素符合条件,some返回true (every要求每一个都符合)
        const arr = [1, 3, 4, 6, 7];
        // 这个数组里面有没有元素大于6的
        const result = arr.some((value) => value > 6);
        console.log(result); //true

        /* 
        every 和 some 一起记
        every 要求全部都符合
        some 最少有一个符合即可 
         */

数组方法- 其他方法以及属性

image-20220421224952474

伪数组转真数组方法

数组 = [ ...伪数组 ]

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
    />
    <title>09-伪数组转真正的数组.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <ul>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
    </ul>
    <script>
      const lis = document.querySelectorAll('li'); // 伪数组
      // const liList=domToArr(lis);
      // console.log(liList.every);

      // 现在先简单用一个
      // const liList=[...伪数组]
      const liList=[...lis];// 最简单的转伪数组的方式  先这么用 

    </script>
  </body>
</html>

面向对象 -概念-思维

一种编程行业通用的写项目级的代码的思维,引导我们如何编写 高质量的代码,万物皆对象-看待事物的角度,( 属性: 数据, 行为: 动作 (方法))代码特点是封装和继承

概念:一般写大型项目才使用

思维:看成两部分

1属性:(颜色,名字身高等)

2行为:(修改颜色,设置文字大小,等)

      // 分析代码 功能 或者任何事情 面向对象的思维
      // 属性
      // 行为

      // 孙悟空
      // 属性: 名字孙悟空、颜色、黄色、身高150、毛发多、
      // 行为:会走路、会技能72变、

      // 思维 去分析 轮播图
      // 属性 有图片、有小圆点(索引器)、有上下箭头 、居中显示
      // 有小圆点(小,选中,蓝色,未选中,黑色,中间存在间隔)
      // 行为 
      // 自动轮播、点击上下页切换显示、点击指示器跳转显示、显示渐变效果显示

      // 结合写代码的经验 从上面整理出有效的属性和行为 ->构造代码的结构 

      // 对象 就是指对象类型 Object 

面向对象-字面量

  • 简单粗暴
  • 不适合创建多个同样类型的对象的场景
  • 只能在小案例使用,不好修改样式

面向对象-构造函数

专业术语

会把 createPerson 叫做 构造函数

会把 createPerson 创建出来的对象 叫做 实例

this.属性值 和 new 创建对象 配套使用

公式:

1 声明一个函数

function createStudent(name,age){
      // 2 给this赋值
          this.name=name
          this.age=age
       }
      // 3 通过new的方式来创建对象 就叫实例
       const obj1=new createStudent('悟空',18)
       console.log(obj1);

后续添加属性就this. 属性值 形参也要有几个 写几个

  //   后续添加属性 就 this. 属性值    形参也要有几个 写几个
      function createStudent(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
      }
      const obj1 = new createStudent("悟空", 18, "男");
      console.log(obj1);

构造函数的工作原理:

  1. 开辟空间
  2. 将新的创建的对象对象构造函数中的this
  3. 为对象赋值
  4. 将创建好的对象的地址返回

13-构结函数的弊端

外部声明函数 方法 在大型项目中 会污染了全局变量

缺点: 代码不够优雅 污染了全局变量 以后不能写 say方法,很容易就覆盖()

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
    />
    <title>16-构造函数-性能问题.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <script>
      // 构造函数的 方法 都会通过类似的这种方式 来实现 多个实例的方法共享
      function say() {
        console.log('你好');
      }
      function CreatePerson(name) {
        this.nickname = name;
        this.say = say;
      }
      // function say() {
      //   console.log("学生你好");
      // }
      // function createStudent(params) {
      // }

      const obj1 = new CreatePerson('悟空');
      const obj2 = new CreatePerson('八戒');
      console.log(obj1);
      console.log(obj2);

      console.log(obj1.say === obj2.say); // true  这个代码是合理的 优化过
      console.log(obj1.say === obj2.say); // false  不够好 性能不够好  两个say占据了两个内存

      // 函数函数 方法提取出去 这套代码
      // 优点: 方便代码维护、也解决了性能 obj1.say === obj2.say

      // 缺点:  代码不够优雅 污染了全局变量 以后不能写 say方法,很容易就覆盖()
    </script>
  </body>
</html>

原型对象-勾结函数(好用,没弊端)

在原有的结构函数上使用原型对象

  • 原型的单词是 prototype, 原型的这个名字是行业内共同认可的名字。

  • 原型本质是一个对象,理解为 JavaScript 自动帮我们添加的

  • 原型是 JavaScript 自动帮我们在定义构造函数的时候添加的

  • 所有构造函数的实例,共享一个原型

  • 原型上一般是挂载函数

    image-20220421230200233

    主要:

    构造函数内只放属性 name 、age、color、height

    对应原型上 都是放 方法 = 函数

          // 原型对象 是任何构造函数对存在的一个对象 prototype
          // 作用: 构造函数看是人, 原型对象 就是人的DNA
          // 如果我们修改了DNA,那么通过构造函数创建实例都会一起发生修改
          // 如果我们在DNA上新增了一些东西,对应实例一样会被新增
    
          function CreatePerson(name) {
            this.name = name;
          }
          // 原型对象
          // console.log(CreatePerson.prototype);
          // 在DNA上新增 东西
          CreatePerson.prototype.say = function () {
            console.log("你好");
          };
          const obj1 = new CreatePerson("悟空");
          const obj2 = new CreatePerson("八戒");
          // obj1.say();
          // obj2.say();
    
          function CreateStudent() {}
    
          CreateStudent.prototype.say = function () {
            console.log("学生你好");
          };
    
          // console.log(obj1.say === obj2.say);// 没有性能问题
          // 有污染全局变量的问题吗  没有
          // CreatePerson.prototype.say
          // CreateStudent.prototype.say
    
          // 小结 原型对象-构造函数 一般情况
          // 构造函数内只放属性 name 、age、color、height
          // 对应原型上 都是放 方法 = 函数
    

    面向对象-案例

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
        />
        <title>20-面向对象-初体验.html</title>
        <style>
          * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
          }
          .scale{
            border-radius: 50%;
            animation:ani-scale 3s linear infinite alternate ;
          }
          @keyframes ani-scale {
            0%{
              transform: scale(0.1);
            }
            100%{
              transform: scale(2);
            }
          }
        </style>
      </head>
      <body>
        <button class="btn1">控制图片1</button>
        <script>
          /* 
          需求: 通过 new MyImg("图片地址")  页面上就会多一个图片标签 
    
          1 页面上多一个图片的本质代码
            1 const img = document.createElement("img");
            2 img.src="图片地址"
            3 document.body.appendChild(img); 
    
          2 new的方式来创建图片 
            new MyImg 做了什么事情  => 调用了一个构造函数 MyImg
    
    
          通过 点击了按钮,控制对应的图片 放大缩小效果 
    
              1 css来实现放大缩小 
              2 按钮 绑定点击事件 
           */
          // const img1 = new MyImg('./images/1.png'); // 页面上多一个图片标签
    
          function MyImg(src) {
            const img = document.createElement('img');
            img.src = src;
            document.body.appendChild(img);
    
            this.dom=img;// 把图片dom元素 添加到 this对象的一个属性 dom属性上了
          }
    
          MyImg.prototype.scale=function(){
            // 图片放大缩小的本质是不是给图片的dom元素 添加一个class
    
            // 获取一下 上一个函数中的一个变量 img
            // 原型上 想要获取另外一个函数中的变量 
            // console.log(this.dom);
            this.dom.classList.add("scale");
    
          }
         
    
          const imgModel = new MyImg('./images/s_02.jpg');// 创建了一个对象 
    
          const btn1=document.querySelector(".btn1");
    
          btn1.addEventListener("click",function () {
            imgModel.scale();// 要调用这个对象的放大缩小的方法
          })
    
    
    	 /* 
          需求:
          1   通过行代码 const divModel = new Div("这个是普通的地址");      页面中出现对应的一个div标签
          2   给按钮绑定点击事件 触发了
               divModel.changeColor("red");  这个div的背景颜色变成红色
               divModel.changeColor("yellow");  这个div的背景颜色变成黄色
    
          分析:
          1 Div 是一个构造函数
          2 Div 构造函数 在原型上有一个方法 changeColor
    
    
          3 const divModel = new Div("这个是普通的地址");  
            这行代码实际的作用 页面中出现一个div
            1 const div=document.createElement("div");
            2 div.innerText="文本内容"
            3 document.body.appendChild(div) 
    
          4 divModel.changeColor("yellow"); 这个div的背景颜色变成黄色
            ???.style.backgroundColor="yellow"
           */
    
          function Div(text) {
            const div = document.createElement('div');
            div.innerText = text;
            document.body.appendChild(div);
            this.dom = div;
          }
          Div.prototype.changeColor = function (color) {
            // this.dom = div;
            this.dom.style.backgroundColor = color;
          };
          Div.prototype.setFont = function (px) {
            // this.dom = div;
            this.dom.style.fontSize = px;
          };
    
          const button=document.querySelector("button");
    
          const divModel1 = new Div('这个是普通的div1');
          
          button.addEventListener("click",function () {
            divModel1.changeColor("red");
            // 新功能
            divModel1.setFont("100px");// 希望div中的文字 大小变为100px
       
          })
        
        </script>
      </body>
    </html>
    
    

    面向对象-指定标签添加图片

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
        />
        <title>03-面向对象的案例.html</title>
        <style>
          * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
          }
        </style>
      </head>
      <body>
        <ul>
          <li>1</li>
          <li>2</li>
          <li>3</li>
          <li>4</li>
          <li>5</li>
        </ul>
        <script>
          /* 
          需求
          1 const imgModel =new MyImg("图片地址")  (不要直接插入到body标签上)
          2 imgModel.append("父元素的选择器"); 希望可以在父元素里面插入一个img 
    
          3 根据给到的需求
            1 先拆分出 代码的结构 要定义构造函数吗  原型上要写什么方法
            2 根据给到的代码具体需求 结合 底层js+webAPI的知识 来实现 封装的功能
            3 在以前更多的是学习如何直接写代码问题 ,现在也是在写代码 -  直接解决问题,通过封装代码(提高的能力)->解决问题 
           */
    
          function MyImg(src) {
            const img = document.createElement("img");
            img.src = src;
            this.dom = img;
          }
    
          MyImg.prototype.append = function (parentSelector) {
            // 通过 this.dom  获取到 构造函数中创建好的图片img对象
            // 希望可以在父元素里面插入一个img  底层的webAPI代码是什么
            // document.body 父元素
            // 父元素.appendChild(子元素);  // img 创建的元素
            document.querySelector(parentSelector).appendChild(this.dom);
          };
    
          // 获取指定的li标签
          // const li=document.querySelector("li:nth-child(3)");
    
          // 先创建一个图片标签
          const imgModel = new MyImg("./images/s_10.jpg");
          // 指定位置来插入元素
          imgModel.append("li:nth-child(3)"); // 图片插入到指定的父元素中
        </script>
      </body>
    </html>
    
    

02-JS-高级-原型继承(call)-函数默认值-拓展-剩余运算符

call 就是借用别人的 属性 方法

1 - call -调用属性

如父亲的属性 儿子想要调用

父元素.call(this,形参1,形参2等等) this是指自己 谁调用this this就是指谁

this. 属性 this. 只能在属性上使用 方法不能使用 方法要使用对象名称

      //父亲
      function Person(name, age, height) {
        this.name = name;
        this.age = age;
        this.height = height;
      }
      //儿子
      function Student(name, age, height, color) {
        // 这一行代码解决了继承的问题!!
        // call 借用别人的方法
        // 谁有方法
        // 谁想要借用person方法  this = 实例 = 下面代码的s1

        //this 指的是自己(Student)   谁调用this  谁就是this
        Person.call(this, name, age, height); //儿子想要使用父亲的某些代码, 父亲方法.call(this,形参1,形参2)

        // this.name = name;
        // this.age = age;
        // this.height = height;
        this.color = color;
      }
      const p1 = new Person("小明", 18, 180);
      const s1 = new Student("小红", 28, 170, "red");
      console.log(p1);
      console.log(s1);

call-调用方法

如调用方法 超人会飞 普通人调用

父元素 .方法 .call (要调用的对象名称)

      const obj={
        name:"超人",
        skill(){
          console.log(this.name +" 会飞");
        }
      }
      // 超人有技能 会飞 
      const obj2={
        name:"普通人"
      };

      // 让普通人  借 一下超人的技能 skill  固定的规则 
      obj.skill.call(obj2);

方法内可以给对象添加属性

本质可以给对象添加新的属性

      const car = {
        name: '装甲车',
        add: function (username, age) {
          // 本质 可以给car添加新的属性
          this.username = username;
          this.age = age;
        },
      };

      car.add('发动机', 100);
      console.log(car);  //   {name='装甲车',username='发动机',age=100}

可以实现了一个空对象obj通过call的使用来实现了 借别人的方法add来给obj添加新的属性

      const car = {
        name: '装甲车',
        add: function (username, age) {
          // 本质 可以给car添加新的属性
          this.username = username;
          this.age = age;
        },
      };

      // car.add('发动机', 100);
      // console.log(car);


      const obj = {};
      // car.add.call(obj); // obj 想要借用 添加属性的方法
      car.add.call(obj, '发动机', 200); // call 传入参数  add.call(谁要借用,被借用的方法的形参1,被借用的方法形参2)
      console.log(obj);

继承-call-prototype

想要实现继承的功能 分两个部分

1 属性的继承

父元素.call(this,其他参数)

person.call(this,name,age)

2 方法的继承

儿子的原型.方法 = 父亲的原型.方法

studen.prototype.say = person.prototype.say

      // 对象 两个大的特点
      // 属性 - 属性的继承
      // 行为-方法
      // 让儿子也具有父亲的行为  =>  把父亲的DNA 给到儿子即可
      // 给儿子添加行为 儿子的原型上添加
      // 父亲的行为 存放在父亲原型上

      function Person(name, age) {
        this.name = name;
        this.age = age;
      }
      Person.prototype.say = function () {
        console.log(this.name, this.age); // 我是谁 我的年龄是
      };
      Person.prototype.show = function () {
        console.log(this.name + " 打螺丝");
      };

      function Student(name, age, color) {
        // name age person里面已经有定义
        // 借用一下
        Person.call(this, name, age);
        // color person里面没有的 需要自己来定义
        this.color = color;
      }

      const s1 = new Student("小学生", 18, "yellow");

      // 把父亲的行为 也设置到儿子
      Student.prototype.say = Person.prototype.say;
      Student.prototype.show = Person.prototype.show;
      s1.say();
      s1.show();
      //   console.log(s1);
      /* 
      总结
      想要实现继承的功能 分两个部分
      1 属性的继承
        Person.call(this,其他参数)
      2 方法的继承
        儿子的原型.say =  父亲的原型.say 
      
       */

案例

      /* 
      封装 代码 实现以下的功能
      1 父亲   Element
        1 属性 dom   this.dom
        2 行为 实例.append(父元素标签的选择器)
      2 儿子1  ElementDouble  div
        1 继承父亲 Element  
          属性 dom
          行为 append
      3 儿子2  ElementSingle  img 
          属性 dom
          行为 append

      4 当执行以下代码时 出现对应效果
        1 const divModel = new ElementDouble("div","div内的文字")
        2 divModel.append("body") ;  body标签可以出现 一个 div 

        1 const imgModel = new ElementSingle("img","图片地址")
        2 imgModel.append("body");  body标签可以出现 一个图片 
       */

      //父亲
      function Element(tagName) {
        const dom = document.createElement(tagName);
        this.dom = dom;
      }
      Element.prototype.append = function (parentSelector) {
        document.querySelector(parentSelector).appendChild(this.dom);
      };

      // 儿子1
      function ElementDouble(tagName, content) {
        Element.call(this, tagName);
        this.dom.innerText = content;
      }
      ElementDouble.prototype.append = Element.prototype.append;


      // 儿子2
      function ElementSingle(tagName, src) {
        Element.call(this, tagName); //继承父亲的属性
        this.dom.src = src;
      }
      //   继承父亲的行为
      ElementSingle.prototype.append = Element.prototype.append;

      const divModel = new ElementDouble("div", "这是div里面的内容");
      divModel.append("body");
      const imgModel = new ElementSingle("img", "./images/s_10.jpg");
      imgModel.append("div");

函数参数默认值 es6

注意:

默认值就是 (调用者)你没有, 就使用我, 你有,使用你的

如果你给我传递了形参 我就输出你的形参

      function show(msg = '你好',str="你我都好") {
        console.log(msg,str);
      }

      show(); // 没有传递参数  输出你好  你我都好
      show('大家好'); // 输出 大家好   你我都好
      show('大家好',"世界美好"); // 输出 大家好  世界美好

对象-简写

简写 如果变量的名字和属性的名字 一致的话, 对象可以简写

const name = 123 对象 = { name } 对象.name 就能获取它的值

      // 简写 如果变量的名字和属性的名字 一致的话,对象可以简写

      // const obj = {
      //   // 属性名 和 属性值
      //   username: 123,
      // };

      const username = 123;
      const color = 'red';

      const say = function () {};
      function show() {}

      // 很常用
      const obj = {
        username, // username:username
        color, // color : color
        say,
        show,
        height: 100,
      };

      obj.height = 200;
      console.log(obj);

      // 对象中方法的简写
      const person={
        show:function(){
          console.log("show");
        },// 常规写法
  
        say(){
          console.log("say");
        } // es6 关于 方法简写
      }
      person.show();
      person.say();

对象-数组-解构

对象-解构:

const { username,height } = { username:'悟空',height:200 }

打印 username,height 就是 username: '悟空 ', height:200

数组-解构:

const arr = [1 ] > const [ a, b ] = arr 打印 a=1 b=undefined

const [ a, b ] = [ 100, 200 ] > 打印 a = 100 , b = 200

解构+默认值:

如果右边对象中没有height 属性那么 height变量 = 1000

const { username,height = 1000 } = { username:'悟空',height:200 }

c 在右边找不到对应的数据 c 就使用默认值 300

const [a,b,c=300]=[100,200];

代码示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div data-index="100" data-num="200">div</div>
    <script>
        //  dataset本身就是一个对象,所以可以用解构来获取他的值
      const { index,num } = document.querySelector('div').dataset;
      console.log(index);//100
      console.log(num);//200

      //数组解构
      //   const arr = [1, 2, 3, 4];
      //   const [a, b, c, d] = arr;
      //   console.log(a, b, c, d);

      //   //对象解构
      //   const obj={
      //       username:'悟空',
      //     height:188
      //   }
      //   const {username,height}=obj
      //   console.log(username,height);

      //  数组解构 + 默认值
      const arr = [1];
      //   const [a,b]=arr// a=1  b=undefined

      // b = 2 默认值 (你没有,就使用我,你有,使用你的)
      const [a, b = 2] = arr;
      console.log(a, b); //a=1  b=2

      //对象 解构  + 默认值
      const obj = {
        username: 100,
      };
      const { username, height = 200 } = obj;
      console.log(username, height);

      /* 
      小结
      1 解构 对象 和 数组上
        对象 
        const  { username,height } = {username:"悟空",height:200}
        数组
        const [a,b]=[100,200];

     2 解构 + 默认值
       如果 右边的对象中没有height 属性 那么 height变量 =  1000 
       const  { username,height=1000 } = {username:"悟空",height:200} 
        
       c 在右边找不到对应的数据 c 就使用默认值 300 
        const [a,b,c=300]=[100,200];
       */
    </script>
  </body>
</html>

扩展-剩余-延展运算符 ...

合并数组-伪数组转真数组

扩展运算符可以应用于 合并数组

扩展运算符可以应用于 合并数组

arr1=[1,2,3] arr2=[3,4,5]

arr1.push( ... arr2 ) 结果是: arr1[1,2,3,4,5]

可以将 伪数组 转 真数组

数组 = [ ... 伪数组 ]

      // const lis = document.querySelectorAll('li');// lis 伪数组 没有map方法
      // const newList = [...lis]; // 如何理解 ? 转成真正的数组

剩余-数组-对象

剩余-数组-对象

获取剩下数组

注意: 和解构不同的是 加入 ... 那么他获取的值就是数组

在数组中 放进 ... 就可以后面的内容 存进一个新数组中 就算后面是没内容 那也返回空数组

数组中 const [a,b,...c]=[1,2,3,4,5,6,7]; // c =[3,4,5,6,7]

      // 获取剩下 数组
      // const [a,b,...c]=[1,2,3,4,5,6,7];
      // console.log(a,b); // 1 , 2
      // console.log(c);// [3,4,5,6,7]

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

获取剩下对象

在对象中 放进 ... 就可以后面的内容 存进一个新对象中 就算后面是没内容 那也返回空对象

对象中 const { a,...d } = { a: 1, b: 2, c: 3 }; // d = {b:2,c:3 }

      // 获取剩下 对象
      // const { a, ...c } = { a: 1, b: 2, c: 3 };
      // const { a,b,c ,...d } = { a: 1, b: 2, c: 3 };
      // console.log(c);// ? {b:2,c:3}
      // console.log(d); // ? {}

获取剩下 用在函数的形参上的和

也能计算数据和的功能

      function calc(...args) {
        // args 数组 装载这所有传给calc的参数
        // console.log(args);
        // 声明一个变量
        let sum = 0;
        args.forEach((value) => (sum += value));
        console.log(sum);
      }
      calc(1, 2); // ? [1,2]
      calc(1, 2, 3); // [1,2,3]
      calc(1, 2, 3, 4); // [1,2,3,4]

计算最大值得写法

      function getMax(...args) {
        // args= 数组  接收 所有传递给 getMax方法的 参数
        // console.log(args);
        // 计算最大值 的
        let max = args[0];
        args.forEach((value) => {
          if (value > max) {
            max = value;
          }
        });
        console.log(max);
      }

展开-延展-数组-对象

展开运算符 对数组操作

在前面新增一个元素 后增同理

const arr = ["a", "b", "c"]; const newArr=[ ...arr ,' d'] 打印: [ "a", "b", "c",'d' ]

      // 展开运算符 对数组操作
      const arr = ["a", "b", "c"];
      // 在数组的后面 新增一个 元素 'd'
      // const newArr=[...arr,'d'];

      // 在数组前面 新增一个属性 w
      // console.log(newArr);
      // const newArr = ['w', ...arr];
      // console.log(newArr);
      // arr.push
      // arr.unshift
      // 中间 无法使用 ...
      // splice 来实现

展开运算符 对对象操作

注意:

需要给新对象 重新声明 对象 因为引用类型都是指向同一地址,一旦修改数据,另一个也会改变

      // 展开 ... 用法
      const obj = {
        username: '悟空',
        height: 200,
      };

      // // 新创建一个对象 这个对象 具有 所有 obj的属性
      // // 同时 还有多一个属性,color


      // 建议这做  互补影响
      const newObj = { ...obj, color: 'yellow' }; // 给newObj 开辟新的内存空间
      // const newObj={ username:"悟空",height:20}; // 给newObj 开辟新的内存空间
      newObj.username = '八戒';
      newObj.weight = 100;
      console.log(obj);
      console.log(newObj);

数组去重案例 - some方法

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
    />
    <title>21-数组去重.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <input type="text" />
    <ul></ul>
    <script>
      /* 
      1 输入框绑定键盘按下事件
        1 判断按下的是不是 回车键
        2 是的话 获取输入框的值
        3 判断当前要显示的数据 是否已经存在于数组中 filter 可以 some可以
          如果是已经存在 就不要继续添加
          如果是不存在  就继续添加
        4 把它添加到数组中
        5 写一个方法 把数组的数据 拼接成li标签,插入到 ul中
       */
      const input = document.querySelector('input');
      const ul = document.querySelector('ul');
      const arr = ['a', 'b'];
      render();

      input.addEventListener('keydown', function (event) {
        //判断按下的是不是回车
        if (event.key === 'Enter') {
          // console.log(this.value);

          // some 如果数组中有一项 是返回了true 整个some方法就返回了true
          // 调用some方法的时候,在它的回调函数中 拿数组中的元素 和 当前要添加的元素 做比较 如果相等 就返回true 表示找到了重复

          const isHas = arr.some((value) => value === this.value); // 在我的数组中找到了和你待添加的元素 一样的值 返回true
          if (isHas) {
            // 有重复了 不要再添加
            console.log('有重复了 不要再添加');
          } else {
            // 没有重复 你可以添加
            // 把它添加到数组中
            arr.push(this.value);
            // 数组发生了改变 重新调用render方法 来实现页面的渲染
            render();
          }
        }
      });

      function render() {
        const html = arr.map((value) => `<li>${value}</li>`).join('');
        ul.innerHTML = html;
      }
    </script>
  </body>
</html>

数组去重-filter方法

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
    />
    <title>21-数组去重.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <input type="text" />
    <ul></ul>
    <script>
      const input = document.querySelector('input');
      const ul = document.querySelector('ul');
      let arr = ['a', 'b'];
      render();

      input.addEventListener('keydown', function (event) {
        if (event.key === 'Enter') {
          // filter 来解决
          // filter 过滤
          // 先过滤出  和当前的输入框的值 不相等的 数据
          // 然后再添加
          // 当前输入框的值 "d"
          // 我数组 ['a','c','d']
          // 数组过滤 不包含 "d"  => ['a','c']
          // ['a','c'] 再次添加 'd' 进去 就可以了

          // 过滤出不包含 当前输入框的值的数组
          const newArr = arr.filter((value) => value !== this.value);
          // debugger
          // 让我们的旧的数组 等于你过滤后的数组
          arr = newArr;
          arr.push(this.value);
          render();
        }
      });

      function render() {
        const html = arr.map((value) => `<li>${value}</li>`).join('');
        ul.innerHTML = html;
      }
    </script>
  </body>
</html>

03-JS-高级-Set数组去重

set数组去重

  1. set对象 是es6 才推出

  2. 注意的功能 去重处理

  3. set.add(1); 如果原数组已经有了,那么就不会添加进去

  4. set是一个对象,不是一个数组

  5. 实现 使用set转成数组的时候,需要考虑 ( set对象转-数组 数组-转成对象 )

  6. 数组-转成对象 new Set( beforeArr )

  7. set对象转-数组 const arr = [ ...set ]

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
        />
        <title>01-set数组去重.html</title>
        <style>
          * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
          }
        </style>
      </head>
      <body>
        <script>
          /* 
          1 set对象 是es6 才推出 
          2 主要的功能 去重处理  
             set.add(1);
          3 set是一个对象,不是一个数组!! 
          4 实现 使用set转成数组的时候,需要考虑 (set对象转-数组    数组 - 转成对象)
            数组 - 转成对象  new Set(beforeArr)
            set对象转-数组   const arr=[...set];
    
           */
    
          //  0 有时候 先设置一个初始数组 里面已经存在一些数据
          // 在创建set的对象的时候,把数组传给它
          const beforeArr=['a','b',3,4];
    
          //  1 set对象 需要被new 出来
          const set = new Set(beforeArr);// 数组转成set对象
    
          // 2 给set添加数据的时候 使用 add方法  
          set.add(1);
          set.add(2);
          set.add(2);// 发现有重复数据了,自己内部过滤
          set.add(2);// 发现有重复数据了,自己内部过滤
          set.add(2);// 发现有重复数据了,自己内部过滤
          set.add(2);// 发现有重复数据了,自己内部过滤
    
          // 3 打印set 看一下
          console.log(set);
    
          // 4 set 转成 数组(map、forEach。。。)
          const arr=[...set];
          console.log(arr);
    
        </script>
      </body>
    </html>
    
    

call apply bind: 修改this指向和传递参数

image-20220424224356519

1, 修改this指向- call : obj.skill.call(调用者) 传递参数- call: obj.skill.call(person,参数1,参数 2)

      const obj = {
        name: '老王',
        skill() {
          console.log(this.name + '  翻墙');
        },
      };

      const person = {
        name: '大郎',
      };

      // call 方式来修改this的指向
       obj.skill.call(person);// 大郎 借用老王的方法
      const obj = {
        name: '老王',
        skill(a, b) {
          console.log(this.name + ' ' + a + ' ' + b);
        },
      };

      const person = {
        name: '大郎',
      };

     obj.skill.call(person,1,2);// 传参

计算最大与最小值 这种事es6 主流的常用方法call方法

       const arr=[1,2,3,4];
	   console.log(Math.min(...arr));  //最小值
       console.log(Math.max(...arr));  //最大值

2, 修改this指向- apply: obj.skill.apply(person) 传递参数- apply: obj.skill.apply(person,[ 参数1,参数2 ])

      const obj = {
        name: '老王',
        skill() {
          console.log(this.name + '  翻墙');
        },
      };

      const person = {
        name: '大郎',
      };
      // apply 方式来修改this的指向
      obj.skill.apply(person); // 大郎 借用老王的方法
      const obj = {
        name: '老王',
        skill(a, b) {
          console.log(this.name + ' ' + a + ' ' + b);
        },
      };

      const person = {
        name: '大郎',
      };
	obj.skill.apply(person, [1, 2]); // 数组

3, 修改this指向-const func = obj.skill.bind(person); func();

      const obj = {
        name: '老王',
        skill() {
          console.log(this.name + '  翻墙');
        },
      };

      const person = {
        name: '大郎',
      };   
	const func = obj.skill.bind(person);

   func(); //大郎 调用老王的方法

3.1 传递参数 const func = obj.skill.bind(person); func(参数1,参数2)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
    />
    <title>04-bind-call-apply修改this指向.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <script>
      /* 
      1 传递参数的时候不同写法上 (下一节课再来讲解)
       */

      const obj = {
        name: '老王',
        skill(a, b) {
          console.log(this.name + ' ' + a + ' ' + b);
        },
      };

      const person = {
        name: '大郎',
      };

      // obj.skill.call(person,1,2);// 传参
      // obj.skill.apply(person, [1, 2]); // 数组

      // apply 方法计算
      // 在早些时候 我们是这样来计算 数组最大值和最小值
      // 借用 Math.max方法 目的不是修改this指向
      // 而是 计算数组最大值
    //   const arr=[1,2,3,4];
    //   const max = Math.max.apply(null,arr);  //最大值
    //   const min = Math.min.apply(null,arr);  //最小值


      // 这种 是 es6 主流的 常用方法 call方法
      // const arr=[1,2,3,4];
      // console.log(Math.max(...arr));
      // console.log(Math.min(...arr));

      const func=obj.skill.bind(person);
      func(1,2);


      /* 
      1 bind call  apply 都可以实现修改this指向
      2 代码写法上有区别
        1 obj.skill.call(person);
        2 obj.skill.apply(person);
        3 const func = obj.skill.bind(person);
          func();
      3 传递参数
        1 obj.skill.call(person,参数1,参数2)
        2 obj.skill.apply(person,[参数1,参数2])
        3 const func = obj.skill.bind(person);
          func(参数1,参数2)
      
       */
    </script>
  </body>
</html>

箭头函数-this的指向

大部分情况,对于普通函数,this等于这个函数的调用者 ( 例外 - bind, call, apply )

大部分情况,对于箭头函数,this等于window

箭头函数和this 一起用得话,要慎用!!! 例外 ( 面向对象用法 )

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
    />
    <title>06-箭头函数-this指向.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <button>点击我 我就改变颜色</button>
    <script>
      // 在js中,顶级的对象 就是window

      // 定义一个函数 形式是箭头函数的
      // const func = () => {
      //   console.log(this);
      // };

      // func(); //window

      // const obj = {
      //   name: '悟空',
      //   say: () => {
      //     console.log(this);
      //   },
      // };
      // obj.say(); // window

    //   const obj1 = {
    //     name: '悟空1',
    //     obj2: {
    //       name: '悟空2',
    //       say: () => {
    //         console.log(this);
    //       },
    //     },
    //   };
    //   obj1.obj2.say();//window

      const button = document.querySelector('button');
      button.addEventListener('click', function () {
        console.log(this); // this = button
      });
      button.addEventListener('click',  ()=> {
        console.log(this);// this = window
      });

      /* 
      大部分情况,对于普通函数,this 等于这个函数的调用者
        (例外 - bind、call、apply)
      大部分情况,对于箭头函数,this 等于window
        箭头函数和this 一起用的话,要慎用!! 
        例外(面向对象用法,)
       */
    </script>
  </body>
</html>

es6 的面向对象 - class

image-20220424231506278

语法:

      class Person {
      可以在这直接声明属性如:
        username='小米'
和在下面  this.username='小米' 是等价的
        // constructor 会在 new Person的时候触发
        constructor(name) {
          // console.log("开始创建对象啦");
          this.name = name;
        }
        // 直接写行为  而且可以写多个方法
        say() {
          console.log('say方法被调用啦 ' + this.name);  
        }
        fly() {
          console.log('会飞');
        }
        sing() {
          console.log('唱歌');
        }
      }
      // es6 面向对象 引出新的语法 类 class
      class Person {
        // 方法 constructor 在es6 构造函数
        // constructor 会在 new Person的时候触发
        constructor(name) {
          // console.log("开始创建对象啦");
          this.name = name;
        }

        // 直接写行为
        say() {
          console.log("say方法被调用啦 " + this.name);
        }
        fly() {
          console.log("会飞");
        }
        sing() {
          console.log("唱歌");
        }
      }

      // 一样new一个对象
      const p1 = new Person("悟空1");
      const p2 = new Person("悟空2");
      // console.log(p1);

      p1.say();

      console.log(p1.say === p2.say); //true  共用一个方法 节省性能

es6的继承-calss

语法: 子类 extend 父类 这是固定写法 这只是继承父类的方法

容易出错的 写了 extends 和 constructor 没写 super() Must call super constructor in derived class before accessing 'this' or returning from derived constructor 1 如果你写了 extends 而且还写了 constructor 那你必须要在 constructor 调用了方法 super(); 2 如果你只写了 extends 但是你没有写constructor 不需要管super

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
    />
    <title>10-es6-继承.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <script>
      //父亲
      class Person {
        constructor(name) {
          this.name = name;
        }
        say() {
          console.log("say方法我调用啦 " + this.name);
        }
        fly() {
          console.log("父亲的起飞");
        }
      }

      //学生
      // 表示学生要继承父亲
      // extends 直接就实现了继承父亲的方法
      class Student extends Person {
        //
        constructor(name, color) {
          super(name); // 父亲的构造函数 =es5   Person.call(this,name);
          this.color = color;
        }
        // fly(){
        //   console.log("儿子 起飞");
        // }
        // fly = null; // 用儿子的新的null 去覆盖父亲的fly没有父亲的fly
      }

      const s1 = new Student("学生", "red");
      s1.say();
      s1.fly();
      /* 
      容易出错的 写了 extends 和 constructor 没写  super()
      Must call super constructor in derived class before accessing 'this' or returning from derived constructor
      1 如果你写了 extends 而且还写了 constructor 那你必须要在 constructor 调用了方法 super();
      2 如果你只写了 extends 但是你没有写constructor 不需要管super 

      extends 是继承方法   super() 是继承属性 一般配合使用
      继承要继承父亲的属性和父亲的行为
      1 只实现了继承父亲的行为  还没有实现继承父亲的属性 (super 表示可以继承父亲的属性)

       */
    </script>
  </body>
</html>

es6继承

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      //父类  选择器selecto

      class Element {
        constructor(selecto) {
          let dom = document.createElement(selecto);
          this.dom = dom;
        }
        append(personSelecto) {
          //方法插入
          document.querySelector(personSelecto).appendChild(this.dom);
        }
      }

      // 子 继承
      class DivElement extends Element {
        constructor(selecto, text) {
          super(selecto);
          this.dom.innerText = text;
        }
      }

      class ImgElement extends Element {
        constructor(selecto, src) {
          super(selecto);
          this.dom.src = src;
        }
      }

      const divModel = new DivElement("div", "这是div里的文字");
      const imgModel = new ImgElement("img", "./images/s_10.jpg");
      divModel.append("body");
      imgModel.append("body");
    </script>
  </body>
</html>

三种定义方法的写法-最优

      class Preson {
        //性能最好
        say1() {
          console.log("say1");
        }
        say2 = function () {
          console.log("say2");
        };
        say3 = () => {
          console.log("say3");
        };
      }
      const p1 = new Preson();
      const p2 = new Preson();
      console.log(p1.say1 === p2.say1); // true  p1 和 p2 say1方法是同一个-节省内存
      console.log(p1.say2 === p2.say2); // false p1 和 p2 say2方法不是同一个-性能不好
      console.log(p1.say3 === p2.say3); // false p1 和 p2 say3方法不是同一个-性能不好

es5-原型链

原型链:

一个对象 它可以通过 prototype 来 找到被它继承父亲的方法

如果一个对象从底层触发 可以通过 prototype 一层一层往上找到 继承的关系 = 原型链

作用:

1 如果我需要给 某个数据 (字符串、数组、对象) 统一添加一个方法 ,可以直接在原型上添加

2 初学者 不要乱在原型上定义方法 - 影响巨大

      // 1 创建数组的方式 有两种
      // const arr = ['a', 'b', 'c']; // 字面量 常用-直接和简单的写法

      // 2 数组 也是可以被new
      // const arr = new Array('a', 'b', 'c');
      // console.log(arr);

      function Person() {}
      const p1 = new Person();
      // 在 Person的原型上添加一个方法
      Person.prototype.show = function () {
        console.log('自己添加的方法');
      };
      // p1.show();

      // 给js内置的Array数据 原型也添加一个方法试试
      Array.prototype.show = function () {
        console.log('自定义的数组方法');
      };

      const arr = new Array('a', 'b', 'c');
      // const arr = ['a', 'b', 'c'];
      // arr.show();

      // 利用原型对象的方式,在任意的构造函数上添加想要的行为
      // 任意的构造函数 包括 自己定义的构造函数
      // 也包括 js中 -内置就有的构造函数 Array

      // arr.forEach
      // arr.push()
      // arr.map()
      // arr.filter

      // 对象的创建也分两种清空
      // const ojb={};// 字面量 常用 直接 简单
      const obj = new Object(); // 利用构造函数的方式来创建对象
      Object.prototype.show = function () {
        console.log('对象 自己的show方法');
      };
      obj.show();

万物皆对象

利用原型对象的方式,在任意的构造函数上添加想要的行为任意的构造函数, 包括 自己定义的构造函数,也包括 js中 -内置就有的构造函数 Array数组,标签 都可以利用原型对象的方式 添加自己想要的行为

      /* 
      原型链
      一个对象 它可以通过 prototype 来 找到被它继承父亲的方法
      如果一个对象从底层触发 可以通过 prototype 一层一层往上找到 继承的关系 =  原型链 

      // 作用
      1 如果我需要给 某个数据 (字符串、数组、对象) 统一添加一个方法 ,可以直接在原型上添加 
      2 初学者 不要乱在原型上定义方法 - 影响巨大  
      
       */
      // const obj = {
      //   username: '悟空',
      //   say() {
      //     console.log('这个是say方法');
      //   },
      // };

      // //  万物皆对象
      // Object.prototype.show = function () {
      //   console.log('这个是原型上的show方法');
      // };

      // // 你看要 dom对象  大哥大
      // console.dir(document.querySelector("div"));

      // const arr = [];
      // console.log(arr);
      // arr.show();

      // console.log();
      // Math.show()

      // const str="123";
      // console.dir(str.show);
      // str.show();

      //  console.log(obj);// 直接看到定义在自己身上的属性和方法 看不见定义在 原型对象上的属性和方法
      //  console.log([]);
      // const arr=[];
      // arr.push
      // console.log(arr);
      // obj.say();
      // obj.show();
      // const arr1=[];
      // const arr2=[];
      // const arr3=[];


      Array.prototype.forEach=function(){
        console.log("老子罢工了");
      }
      Array.prototype.map=function(){
        console.log("老子罢工了");
      }
      const arr=[1,2,3];
      arr.forEach(); // forEach 循环 到了你这个项目 这个知识用不了 
      // 对于新入门小小员工来说  毁灭性的打击
      // 10多年代码 用不上 心态。。。。

      // arr.map()// 以前我学都是啥 想不开   你要有责任!!