JS-高级-数组的方法-面向对象-原型继承(call)-函数默认值-剩余算符-Set数组去重-es6的继承-原型链

157 阅读3分钟

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

1-箭头函数

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

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

1-箭头函数-代码示例:

<!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>

2 箭头函数-返回对象

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

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

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

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

代码示例:

<!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>

2-数组方法-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}`));

3-数组方法-map

map 根据原来的数组 来返回新的数组

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

公式:

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

const newArr = arr.map((value) => '我的字母是' + value)

打印结果 : arr = [我的字母是'a',我的字母是 'b', 我的字母是'c'];

代码示例:

        // 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>

4-数组方法-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);
      }

代办事项-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>11-待办列表.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
      body {
        background-color: #ccc;
      }
      ul {
        list-style: none;
      }
      li {
        padding: 20px;
        text-align: left;
        font-size: 30px;
        border-bottom: 1px dashed #ccc;
        display: flex;
        justify-content: space-between;
        align-items: center;
      }
      li input {
        margin-right: 10px;
      }
      li button {
        display: none;
        padding: 5px;
      }
      li:hover button {
        display: inline-block;
        cursor: pointer;
      }
      .chk:checked + span {
        text-decoration: line-through;
      }

      h1 {
        margin-bottom: 10px;
      }

      .box {
        background-color: #fff;
        width: 60vw;
        padding: 20px 20px 0;
        margin: 50px auto;
      }
      .box .tool input {
        width: 100%;
        height: 50px;
        text-indent: 20px;
        font-size: 20px;
        font-style: italic;
        color: #666;
        font-weight: 700;
      }
      section {
        height: 50px;
        display: flex;
        justify-content: space-between;
        align-items: center;
      }
      a {
        text-decoration-color: #666;
        color: inherit;
      }
    </style>
  </head>
  <body>
    <div id="app" data-v-app="">
      <div class="box">
        <h1>待办列表</h1>
        <div class="tool">
          <input autofocus="" type="text" placeholder="请输入代办事项" />
        </div>
        <ul></ul>
        <section>
          <span>1 未完成</span><a href="#">清理 <b>0</b> 已完成</a>
        </section>
      </div>
    </div>
    <script>
      const input = document.querySelector(".tool input");
      const ul = document.querySelector("ul");
      const unFinishSpan = document.querySelector("section span");
      const finishA = document.querySelector("a b");
      const a = document.querySelector("a");
      let arr = [];
      const strArr = localStorage.getItem("todo");
      if (strArr) {
        arr = JSON.parse(strArr);
      }

      render();

      input.addEventListener("keydown", function (event) {
        if (event.key === "Enter") {
          // input.value
          arr.push({
            text: input.value,
            checked: false,
          });
          render();
          input.value = "";
        }
      });

      ul.addEventListener("click", function (event) {
        const index = event.target.dataset.index;

        if (event.target.className === "chk") {
          arr[index].checked = !arr[index].checked;
          render();
        } else if (event.target.nodeName === "BUTTON") {
          arr.splice(index, 1);
          render();
        }
      });

      a.addEventListener("click", function () {
        let newArr = [];
        for (let index = 0; index < arr.length; index++) {
          if (!arr[index].checked) {
            newArr.push(arr[index]);
          }
        }

        arr = newArr;
        render();
      });

      // 函数负责把数组数据渲染在页面上
      function render() {
        let html = ``;
        for (let index = 0; index < arr.length; index++) {
          const renderChecked = arr[index].checked ? "checked" : "";
          html += `
           <li>
             <div><input data-index="${index}" type="checkbox" class="chk"  ${renderChecked}  /><span class="false">${arr[index].text}</span></div>
             <button data-index="${index}">X</button>
           </li>
           `;
        }
        ul.innerHTML = html;

        localStorage.setItem("todo", JSON.stringify(arr));

        statistics();
      }
//-------  数组方法 filter  过滤------------------------------------------------------------
      function statistics() {
        // 未完成
        unFinishSpan.innerText =
          arr.filter((value) => !value.checked).length + "未完成";

        // 已经完成
        finishA.innerText = arr.filter((value) => value.checked).length;
      }
    </script>
  </body>
</html>

5-数组方法-every

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

公式:

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

const result = arr.every((value) => value < 5); // 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
      }

单选-全选-every方法判断-案例示例

用到的重点:

两个知识

1 伪数组转真正的数组 let newArr=[...伪数组] ;

2 every 要求数组的每一个元素都符号要求, every才返回true

使用场景, 商品全选 => 每一个小商品都选中, 全选才勾选!!

4 如果 数组 有every方法, list.every 看是不是undefined

不是的话 表示数组有 every方法 list.every() 调用

是 表示数组没有 every方法,不用list.every()

<!DOCTYPE html>

<html>
  <head lang="en">
    <meta charset="UTF-8" />
    <title>08-全选和不全选-every</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

      table {
        border-collapse: collapse;
        border-spacing: 0;
        border: 1px solid #c0c0c0;
        width: 500px;
        margin: 100px auto;
        text-align: center;
      }

      th {
        background-color: #09c;
        font: bold 16px "微软雅黑";
        color: #fff;
        height: 24px;
      }

      td {
        border: 1px solid #d0d0d0;
        color: #404060;
        padding: 10px;
      }

      .allCheck {
        width: 80px;
      }
    </style>
  </head>

  <body>
    <table>
      <tr>
        <th class="allCheck">
          <input type="checkbox" name="" id="checkAll" />
          <span class="all">全选</span>
        </th>
        <th>商品</th>
        <th>商家</th>
        <th>价格</th>
      </tr>
      <tr>
        <td>
          <input type="checkbox" name="check" class="ck" />
        </td>
        <td>小米手机</td>
        <td>小米</td>
        <td>¥1999</td>
      </tr>
      <tr>
        <td>
          <input type="checkbox" name="check" class="ck" />
        </td>
        <td>小米净水器</td>
        <td>小米</td>
        <td>¥4999</td>
      </tr>
      <tr>
        <td>
          <input type="checkbox" name="check" class="ck" />
        </td>
        <td>小米电视</td>
        <td>小米</td>
        <td>¥5999</td>
      </tr>
    </table>
  </body>
  <script>
    let checkAll = document.querySelector("#checkAll");

    let checkboxList = document.querySelectorAll(".ck"); // checkboxList 现在是一个伪数组
    checkboxList = [...checkboxList]; // 伪数组转真数组

    // 商品全选点击 功能
    checkAll.addEventListener("click", function () {
      for (let index = 0; index < checkboxList.length; index++) {
        checkboxList[index].checked = checkAll.checked;
      }
    });

    // // 给每一个商品绑定点击事件
    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;
        //   }
        // });  简化
        let checked = checkboxList.every((value) => value.checked === true);
        // 设置全选按钮即可
        checkAll.checked = checked;
      });
    }
  </script>
</html>

6-数组方法-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 最少有一个符合即可 
         */

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

1650544564319

8-伪数组转真数组方法

公式:

数组 = [ ... 伪数组 ]

代码示例:

<!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>

9-面向对象-概念-思维

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

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

思维: 看成两部分

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

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

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

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

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

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

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

10-面向对象-字面量

  • 简单粗暴
  • 不适合创建多个同样类型的对象的场景
  • 只能在小案例使用,不好修改样式
      const obj1 = { username: '悟空1', tel: 123321 };
      const name1 = 123;
      const obj2 = { username: '悟空2', tel: 123322 };
      const name2 = 123;
      const obj3 = { username: '悟空3', tel: 123323 };
      const name3 = 123;
      const obj4 = { username: '悟空4', tel: 123324 };
      const name4 = 123;
      const obj5 = { name: '悟空5', tel: 123325 };
      // 好处 方便
      // 不方便维护-修改
      // 不想要name属性,修改 username

11-面向对象-工厂函数

  1. 容易理解
  2. 失去血缘关系,无法简单分辨对象的特征
  3. 后期无法实现继承
  4. 缺点 如果有新增属性,就无法修改
      function createPerson(name, age, height) {
        return {
          // name: name,
          username: name,
          age: age,
          height: height,
        };
      }
      // 创建对象
      const obj1 = createPerson("悟空", 18, 150);
      const obj2 = createPerson("八戒", 20, 140);
      const obj3 = createPerson("龙马", 30, 190);
      console.log(obj1);
      console.log(obj2);
      console.log(obj3);

      // 优点 容易维护
      // name => username

      // 弊端 无法实现 继承的作用!
      //要新增一个属性
      function createStudent(name, age, height, grade) {
        return {
          name1: name,
          age1: age,
          height1: height,
          grade: grade,
        };
      }

12-面向对象-构结函数

专业术语

会把 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>

14-构结函数-原型 prototypr

构造函数通过原型分配的函数是所有对象所共享的。 JavaScript规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是个对象,这个对象的所有属性和方法,都会被构造函数所拥有。 我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法。

  • 原型的单词是 prototype, 原型的这个名字是行业内共同认可的名字。
  • 原型本质是一个对象,理解为 JavaScript 自动帮我们添加的
  • 原型是 JavaScript 自动帮我们在定义构造函数的时候添加的
  • 所有构造函数的实例,共享一个原型
  • 原型上一般是挂载函数

1650547774299

主要:

构造函数内只放属性 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
      // 对应原型上 都是放 方法 = 函数

面向对象-案例示例

1-控制图片大小

<!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();// 要调用这个对象的放大缩小的方法
      })
    
    </script>
  </body>
</html>

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>23-面向对象案例.html</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <button>修改颜色</button>
    <script>
      /* 
      需求:
      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>

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

<!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);

2-call-调用方法

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

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

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

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

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

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

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

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

2 可以实现 了 一个空对象 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);

4-继承-call-prototype

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

1 属性的继承

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

Person.call(this, name, age)

2 方法的继承

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

Student.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 
      
       */

继承的案例示例

在页面中插入一个 div 和 图片

如果代码重复实现了 很有可能就是我们要封装的时候

以前的封装 仅仅是封装一个小小的函数而已

现在的封装, 面相对象的思维来封装

封装 属性 父亲

封装 方法 父亲

儿子 去调用

      /* 
      封装 代码 实现以下的功能
      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");

5-函数参数默认值(es6)

注意:

默认值就是 你没有,就使用我,你有,使用你的

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

如果没有给我输出,我就输出你好

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

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

6-对象-简写

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

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();

7-对象-数组-解构

1 解构 对象 和 数组

对象 -解构

​ 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 b 就是 100 200

2 解构 + 默认值

​ 如果 右边的对象中没有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>

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

合并数组-伪转真数组

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

​ 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]; // 如何理解 ? 转成真正的数组

剩余-数组-对象

1 获取剩下数组

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

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

数组中 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); //  []

2 获取剩下对象

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

对象中 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); // ? {}

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

也能计算数据和的功能

      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]

4 求数组最大 小值

计算最大值的写法

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

简写 :Math对象 自己就封装过 计算最大值和最小值的代码

      // Math对象 自己就封装过 计算最大值和最小值的代码
      // console.log(Math.max(1,3,4,2));// 4
      // console.log(Math.min(1,3,4,2));// 1

      function getMax2(...args) {
        // Math.max(1,3,4,2)
        // args=[1,3,4,3]
        // Math.max([1,3,4,3]) =>  Math.max(1,3,4,2)
        // 剩余运算符的

        console.log(  Math.max(...args));
      }
      // getMax2(1,2,3);
      // getMax2(1,2,33);
      // console.log(Math.max(...[1,3,4,3])); //  Math.max(1,3,4,2)

      getMax2(1,2,3,4); // 体现的思想 不再是 剩余 。  展开-延展-拓展 思想 

5 展开-延展-数组-对象

展开运算符 对数组操作

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

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);

9-数组去重案例-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>

9-数组去重-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数组去重-this的指向-传递参数区别-es6的继承-原型链

1-Set数组去重

  1. set对象 是es6 才推出

    1. 主要的功能 去重处理

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

  1. set是一个对象,不是一个数组!!

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

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

​ 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>

1-Set 数据结构

实例方法

add(value):添加某个值,返回 Set 结构本身

delete(value):删除某个值,返回一个布尔值,表示删除是否成功

has(value):返回一个布尔值,表示该值是否为 Set 的成员

clear():清除所有成员,没有返回值

 const s = new Set();
 s.add(1).add(2).add(3); // 向 set 结构中添加值 
 s.delete(2)             // 删除 set 结构中的2值 
 s.has(1)                // 表示 set 结构中是否有1这个值 返回布尔值 
 s.clear()               // 清除 set 结构中的所有值

2-call-修改this的指向-传递参数(es6常用)

1650809421436

1.class 方式来修改this的指向

父类 . 方法 .call (子类) 方法中的 this 就是指向子类

obj.skill.call(person);// 大郎 借用老王的方法

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

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

      // call 方式来修改this的指向
       obj.skill.call(person);// 大郎 借用老王的方法

2.class 方式-传递参数

obj.skill.call(person,1, 2 ); // 传参 直接在 子类 后面以逗号隔开放入即可

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

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

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

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

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

3-apply-修改this的指向-传递参数

1.apply 方式来修改this的指向

父类 . 方法 .call (子类) 方法中的 this 就是指向子类

obj.skill.apply(person); // 大郎 借用老王的方法

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

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

2.apply 方式-传递参数

obj.skill.apply(person, [1, 2]); // 数组 参数要用数组包裹起来

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

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

3.apply 方法计算最大与最小值

在早些时候 我们是这样来计算 数组最大值和最小值

借用 Math.max方法 目的不是修改this指向

而是 计算数组最大值

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

4-bind-修改this的指向-传递参数

1.bind 方式来修改this的指向

bind 不会直接调用 方法 函数 而是 返回一个新的函数

需要我们主动的调养新的函数 调用 方法 ()

const func = 父类 . 方法 . bind (子类);

func ();

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

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

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

2.bind 方式-传递参数

直接在 调用新的 函数中 放入参数 func(参数1,参数2)

3-三种方式的传递参数区别总汇

<!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>

5-箭头函数-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>

6-es6的面向对象-class

语法:

  可以在这直接声明属性如:
    username='小米'

和在下面

constructor(){

this.username='小米' 是等价的

}

      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  共用一个方法 节省性能

7-es6的继承-class

语法:

子类 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

extends 是继承方法 super() 是继承属性 一般配合使用

继承要继承父亲的属性和父亲的行为

1 只实现了继承父亲的行为 还没有实现继承父亲的属性 (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>

继承的小案例:

<!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>

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

say1() {

​ console.log("say1");

​ }

不用 = 好的简写 最好 多个实例共用一个方法 节省性能

      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方法不是同一个-性能不好

9-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()// 以前我学都是啥 想不开   你要有责任!! 

4-拓展 变量的区别-数组方法补充

  1. 使用 var 声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象。
  2. 使用 let 声明的变量,其作用域为该语句所在的代码块内,不存在变量提升。
  3. 使用 const 声明的是常量,在后面出现的代码中不能再修改该常量的值。

1650811822398

var

1650812936403

let

1650812967921

const

作用:声明常量,常量就是值(内存地址)不能变化的量

具有块级作用域

常量赋值后,值不能修改

声明常量时必须赋值 否则会报错

解构赋值-数组-对象

ES6中允许从数组中提取值,按照对应位置,对变量赋值。对象也可以实现解构。

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

如果解构不成功,变量的值为undefined。

 let [foo] = [];//数组中没有值
 let [bar, foo] = [1];//会输出  undefined

按照一定模式,从数组中或对象中提取值,将提取出来的值赋值给另外的变量。

 let person = { name: 'zhangsan', age: 20 }; 
 let { name, age } = person;
 console.log(name); // 'zhangsan' 
 console.log(age); // 20

 let {name: myName, age: myAge} = person; // myName myAge 属于别名
 console.log(myName); // 'zhangsan' 
 console.log(myAge); // 20

构造函数方法:Array.from()

将类数组或可遍历对象转换为真正的数组

let arrayLike = {
    '0': 'a',
    '1': 'b',
    '2': 'c',
    length: 3
}; 
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

方法还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。

      let arrayLike = {
        0: 1,
        1: 2,
        length: 2,
      };
      //里面的值再剩余2
      let newAry = Array.from(arrayLike, (item) => item * 2);
      console.log(newAry);//  2   4

数组方法:find()

用于找出第一个符合条件的数组成员,如果没有找到返回undefined

      let ary = [
        {
          id: 1,
          name: "张三",
        },
        {
          id: 2,
          name: "李四",
        },
      ];
      let target = ary.find((item, index) => item.id == 2);
      console.log(target);//只选中 数组中ID为2 的数组对象

实例方法:findIndex()

用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1

        //用于找到符合条件的数组位置  得到是数组的下标
      let ary = [1, 5, 10, 15];
      let index = ary.findIndex((value, index) => value > 9);
      console.log(index); // 2

实例方法:includes()

表示某个数组是否包含给定的值,返回布尔值

      console.log([1, 2, 3].includes(2)); // true
      console.log([1, 2, 3].includes(4)); // false

string的扩展方法-调用函数

在模板字符串中可以调用函数

 const sayHello = function () { 
    return '哈哈哈哈 追不到我吧 我就是这么强大';
 }; 
 let greet = `${sayHello()} 哈哈哈哈`;  console.log(greet); // 哈哈哈哈 追不到我吧 我就是这么强大 哈哈哈哈

string实例方法:startsWith() 和 endsWith()

startsWith():表示参数字符串是否在原字符串的头部,返回布尔值 endsWith():表示参数字符串是否在原字符串的尾部,返回布尔值

 let str = 'Hello world!';
 str.startsWith('Hello') // true 
 str.endsWith('!')       // true

string实例方法::repeat()

repeat方法表示将原字符串重复n次,返回一个新字符串。

'x'.repeat(3)      // "xxx" 
'hello'.repeat(2)  // "hellohello"