Es6常用的方法

282 阅读7分钟

箭头函数

定义

函数的简写

作用

提高书写效率

语法

<script>
    // 以前写函数的方式 num1 形参
    function func1(num1) {
      // return 返回一个结果
      return num1 + 100
    }
    // console.log(func1(1)); //func1(1) 1 代表实参
    // 箭头函数 函数的简写,可以通过书写效率  =>箭头函数固定搭配
    const func2 = (num1) => num1 + 100 //和上面是相等功能
    // console.log(func2(1)); //调用函数一定要写() 代表执行
 </script>
  1. 没有形参,没有返回值 有2行业务

     // 没有形参一定要写()。
        const func3 = () => {
         console.log('执行业务1');
         console.log('执行业务2');
        }
    
  2. 没有形参,没有返回值,业务只有一行代码,大括号可以省略

     const func4 = () => console.log('执行业务3');
    
  3. 只有一个形参,没有返回值,业务只有一行代码

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

    const func6 = (a, b) => console.log(a + b);
    
  5. 没有形参,有返回值,业务两行代码

     const func7 = () => {
          let a = 100
          return a + 100
        }
    
  6. 没有形参,有返回值,业务一行代码

const func8 = () => {
    //   return 100 + 200
    // }
    // console.log(func8());
    const func8 = () => 100 + 200 //和上述写法 return 100 + 200 功能相等
    // console.log(func8())

注意点:

  1. 箭头函数 ()=>{} 这样是固定搭配,箭头函数是匿名函数,一般做参数传参。

  2. 没有形参和多个形参的时候不能省略括号(),只有一个形参的时候才能省略括号

  3. **(重点)**函数体只有一句,可以省略{ },同时返回函数体的结果,就不能写return;相反如果不省略括号,就要写return。

    const func8 = () => {
        //   return 100 + 200
        // }
        // console.log(func8());
        const func8 = () => 100 + 200 //和上述写法 return 100 + 200 功能相等
        // console.log(func8())
    
  4. return 可以中止函数,后面的代码不再执行,同时return表示的是返回一个结果,所以如果想要获得这个返回值就不能换行写

  5. **(重点)**箭头函数返回对象,想要省略return,要加上()

     const func9=(num)=>({a:123});// => 右边加了小括号 表示想要返回 小括号里面的数据相当于           const func9=(num)=> return {a:123};
    

箭头函数和this指向

大部分情况下,箭头函数和this一起使用,this指向的是window

  const func = () => {
        console.log(this,'这个是箭头函数的this'); //window
      };

      func();

      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

大部分情况下,普通函数和this一起使用,this指向这个函数调用者

    const button = document.querySelector('button');
      button.addEventListener('click', function () {
        console.log(this,'这个是普通函数的this'); // this = button
      });

数组常见的方法

forEach()高阶函数

定义

按顺序为数组中的每个元素调用一次函数

语法

array. forEach(function(value,index,arr),thisvalue)

image-20220504172603683

image-20220504173013830

注意点

forEach类似for循环,但for循环可以通过 break来打断、 forEach不能通过break打断

对于没有值的数组元素,不执行forEach()方法

map()方法

定义

通过指定函数出来数组的每个元素,并返回处理后的数组。换句话说,就是根据原来的数组,按顺序循环返回新的数据,组装成新的数组

语法

array.map(function(value,index,arr),thisvalue)

image-20220504180916823

image-20220504181201868

想要根据数组数据渲染到页面,并且数据独占一行

思路如下:

  1. 先将原数据用map()方法组装成新的div形式数组
  2. 再用数据join(" ")方法,将数组转换成字符串
  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>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() {
        const 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>
        `
        );
        const html = newArr.join('');
        tbody.innerHTML = html;
      }

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

every()方法

定义

检查数组中每个元素是否通过测试

语法

array.every(function(value,index,arr),thisvalue)

image-20220504182804500

image-20220504183213738

注意点

  1. every的返回值是个布尔值,如果数组中的所有元素都通过测试,则返回true,否则返回false
  2. 如果是空数组,调用every 直接返回true

全选和全不选

<!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];// OK 
    // 商品全选点击 功能
    checkAll.addEventListener('click', function () {
      // for (let index = 0; index < checkboxList.length; index++) {
      //   checkboxList[index].checked = checkAll.checked;
      // }
      checkboxList.forEach(function (value,index) {
        checkboxList[index].checked = checkAll.checked;
      })	 // 和上述for循环用法相同
    });
     // 给每一个商品绑定点击事件
     checkboxList.forEach(function (value,index) {
      checkboxList[index].addEventListener('click',function () {
         // 判断是否达到了全选 条件
  // 判断每一个小小的复选框的选中状态 如果都是true,那么就全选
        let checked = checkboxList.every(value=>value.checked)
         // 设置全选按钮即可
        checkAll.checked = checked
      })
    })
 
  </script>
</html>

some()方法

定义

检查数组中每个元素是否通过测试

语法

array.some(function(value,index,arr),thisvalue)

image-20220504182804500

   const arr = [1, 3, 4, 6, 2];
        // 这个数组里面有没有元素大于6的
   const result = arr.some((value) => value > 6);
   console.log(result);  // 输出true

注意点

  1. some 返回值是布尔值。只要数组中有一个元素符合条件,就返回 true,否则返回 false。

filter()方法

定义

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

语法

array.filter(function(value,index,arr),thisvalue)

image-20220504182804500

 const arr = [1, 2, 3, 4, 5, 6, 7];
        // 返回 奇数
  const newArr = arr.filter((value) => value % 2 !== 0);
  console.log(newArr); //输出 [1,  3, 5,  7] 

面向对象

概念:一种编程行业通用的写项目级的代码的思维,世间万物皆是对象-看待事物的思维

看待事物的思维主要可以分成两个部分:

1.属性(一些描述性的数据,一般是固定数值,比如名字,年龄,性别)

2.方法也叫行为(一般是动词,本质是函数,比如说话,唱歌,吃饭,修改颜色,设置字体大小)

创建对象的几种方式

字面量方式创建对象

定义:声明字面式对象

好处:简单粗暴,比较好用

弊端:不方便维护和修改 ,不适合创建多个同类型的, 后期要修改会比较麻烦

语法:const obj = { }

	const obj1 = {name:'悟空1',tel:123451 }
    const obj2 = {name:'悟空2',tel:123452 }
    const obj3 = {name:'悟空3',tel:123453 }
    const obj4 = {name:'悟空4',tel:123454 }
    const obj5 = {name:'悟空5',tel:123455 }

工厂函数创建对象

工厂函数:批量生产对象

好处:容易维护,一改属性名则全改属性名

弊端:没有实现继承的作用;无法简单分辨对象的特征

	 function CreatePerson(name, age, height) {
        return {
          // name: name,
          username:name,
          age: age,
          height: height,
        };
      }
      // 创建对象
      const obj1 = CreatePerson('小红',18,155)
      console.log(obj1);
      const obj2 = CreatePerson('小刚',19,175)
      console.log(obj2);
      const obj3 = CreatePerson('小丽',21,150)
      console.log(obj3);

注意:工厂函数和构造函数会比较相似,但会有不同。

不同之处:

  • 工厂函数是通过返回值输出;而构造函数要先通过this赋值

  • 创建对象方式不同,工厂函数直接创建对象,而构造函数是通过new的方式来创建对象

自定义构造函数创建对象

定义:能够实例化对象的函数,就是构造函数

好处:可以方便的创建对象

弊端:同一个(say)方法占据两份内存

构造函数是一种特殊的方法,主要是用来创建对象时初始化对象,即为对象成员变量赋初始值,总与new 运算符一起使用在创建对象的语句中

  // 1.声明函数
      function Person(name, age) {
        // 2.通过this 赋值 你希望调用obj里面什么的属性,就this.xxx
        // this 和obj1是相关联的
        this.name = name;
        this.age = age;
      }
      //3. 通过new的方式来创建对象 ('小红',18)想要创建什么对象,就传什么对象给(name, age)
	//这一行代码表示的是创建一个对象,同时实例化一个对象,并且给这个对象的属性进行初始化
      const obj1 = new Person('小红',18)  //实例化对象

构造函数的工作原理

  1. 创建一个新对象(开辟空间存储当前对象)

  2. 把this 设置这个新对象

  3. 这个新对象添加新的属性和方法

  4. 把this对象返回

构造函数的特点

  1. 构造函数的首字母必须是大写的,用于区分与普通函数
  2. 内部使用的this对象,来指向即将要生成的实例对象
  3. 使用new 来生成实例对象
  <title>构造函数-性能问题</title>
  </head>
  <body>
    <script>
      // 构造函数的首字母要大写,行内编码规范,固定的
      // 构造函数
      //     function CreatePerson(name) {
      //       // 通过this赋值,创建了name的属性
      //       this.name = name
      //       this.sayHi = function(){
      //         console.log('这个是sayHi的方法');
      //       }
      //     }
      //     // 通过new的方式创建对象
      //     const obj1 = new CreatePerson('小明')
      //     const obj2 = new CreatePerson('小红')
      //     obj1.sayHi()
      //     obj2.sayHi()
      //
      //     console.log(obj1.sayHi === obj2.sayHi); //fasle 表示两个say的方法占据了两份内存。浪费内存,性能不够好

      
      /* 解决浪费内存的方案
    提取同一个say方法 */
      /* 这样的方式容易维护,也解决了性能,但代码不够优雅,会污染全局变量,以后都不能写sayHi的方法,会很容易覆盖 */
      // 提取同一个say 方法
      function sayHi() {
        console.log("这个是sayHi的方法");
      }
      function CreatePerson(name) {
        // 通过this赋值,创建了name的属性
        this.name = name;
        this.sayHi = sayHi; //say函数引用类型,构造函数中的sayHi ,其实和外面的sayHi的内存地址一致的,同一个sayHi方法
      }
      // 通过new的方式创建对象
      const obj1 = new CreatePerson("小明");
      const obj2 = new CreatePerson("小红");
      // obj1.sayHi();
      // obj2.sayHi();

      // console.log(obj1.sayHi === obj2.sayHi); // true 表示在同一个内存上,优化过的性能比较好
    </script>

补充 基本类型和引用类型赋值的不同

// 对于基本类型来说,=  就是复制了一份值
      let num = 100;
      let num2 = num; // 复制值  num和 num2占两给内存 各自不影响
      num2 = 1000;
      console.log(num);

      // 对于引用类似 =  其实把地址拷贝了一份给新的对象  两个数据 公用一份数据
      let person1 = { name: "小明" }; // person1 指向了 一个地址 0x1111 存放悟空
      let person2 = person1; // person2也指向了person1的地址 0x1111  person1和person2 通用一个数据
       // 修改了person2 person1也会发生改变
       person2.name = '小红';
      console.log(person1);
     
         // person2 和person1 共同指向了同一个地址
      console.log(person1 === person2); // true
     
      let obj1 = {}; // 开辟了一个内存
      let obj2 = {}; // 开辟了另外一个内存
      console.log(obj1 === obj2); // false 两个不同的内存地址
    

通过new构造函数来创建对象

原型函数(prototype)

在js中任何一个函数都有一个prototype属性,原型(prototype)就是函数的一个属性,它指向一个对象。

举例子: 构造函数看是人, 原型对象 就是人的DNA

如果我们修改了DNA,那么通过构造函数创建实例都会一起发生修改

如果我们在DNA上新增了一些东西,对应实例一样会被新增

  function CreatePerson(name) {
        // 通过this赋值
        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();

原型链图

原型链是指对象的原型链,所以原型链上的所有节点都是对象,不能是字符串、数字、布尔值等原始类型。

原型链的终点是null,而不是Object.prototype

原因是Object.prototype确实是个特殊对象,我们先假设用它做终点。那么考虑一下,当你取它的原型时应该怎么办?

取一个对象的属性时,可能发生三种情况:

  1. 如果属性存在,那么返回属性的值。
  2. 如果属性不存在,那么返回undefined。
  3. 不管属性存在还是不存在,有可能抛异常

假设Object.prototype是终点了,所以看起来不能是情况1。另外,抛出异常也不是好的设计,所以也不是情况3。那么情况2呢,它不存在原型属性,返回undefined怎么样?也不好,因为返回undefined一种解释是原型不存在,但是也相当于原型就是undefined。这样,在原型链上就会存在一个非对象的值。

所以,最佳选择就是null。一方面,你没法访问null的属性,所以起到了终止原型链的作用;另一方面,null在某种意义上也是一种对象,即空对象,因为null一开始就是为表示一个“空”的对象存在的。这样一来,就不会违反“原型链上只能有对象”的约定。

image-20220511232532026

js的数据类型

值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol。

引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)

**注:**Symbol 是 ES6 引入了一种新的原始数据类型,表示独一无二的值。

检测数据类型的方法

(1)typeof

image-20220511233440469

总结:前6个是基本数据类型, typeof null 返回的结果是错误的,typeof判断不了null的数据类型,可以通过 ===null 来判断 ;引用数据类型object,用typeof判断,除了function 会判断为ok以外,其余都是object,是无法判断出来的。

(2)instanceof

(3)Object.prototype.toString.call()推荐这种检测方法

toString() 是 Object 的原型方法,调用该方法,可以统一返回格式为 “[object Xxx]” 的字符串,其中 Xxx 就是对象的类型。对于 Object 对象,直接调用 toString() 就能返回 [object Object];而对于其他对象,则需要通过 call 来调用,才能返回正确的类型信息。 image-20220511233751989

值类型和引用类型的区别

1、值类型
	1)基本类型数据是值类型
    2)保存与复制的是值本身
    3)使用typeof检测数据的类型
2、引用类型
	1)保存与复制的是指向对象的一个指针
    2)使用instanceof检测数据类型
    3)使用 new() 方法构造出的对象是引用型

原型链继承

1.属性的继承

利用call技术

call定义: 借调 可以让一个对象 来借用另外一个对象的方法

语法

父元素方法.call(谁要借用,谁借用的方法的形参1,谁借用的方法的形参2)

<title>原型-继承</title>
  </head>
  <body>
    <script>
      // 继承的概念:父元素有的,子元素直接拿来用;父元素发生改变,子元素也随之发生改变
      // 构造函数 父元素 (name, age, height) 形参
      function person(name, age, height) {
        // this指的是person
        this.name = name; //对象添加新的属性 ,对象名.新的属性名 = 新值
        this.age = age;
        this.height = height;
      }

      // 构造函数 子元素
      function son(name, age, height,gender) {
        // call 表示借用
        // 父元素方法.call(谁要借用,谁借用的方法的形参1,谁借用的方法的形参2)
        // this = 实例 = s1
       person.call(this,name,age,height)
        this.gender = gender
      }

      // 通过new的方式创建实例
      // const p1 = new person('大头爸爸',32,160)
      const s1 = new son('小头儿子',11,140,'男')

      // 分别打印输出p1,s1
      // console.log(p1);
      console.log(s1);

2.方法的继承

子元素的原型.方法 = 父元素的原型.方法


      // 属性写在构造函数 父元素 (name, age, height) 形参
      // 构造函数首字母要大写
      function Person(name, age, height) {
        // this指的是person
        this.username = name; //对象添加新的数据 ,对象名.新的属性名 = 新值
        this.age = age;
        this.height = height;
      }

      // 方法是写在原型函数中
      Person.prototype.sing = function () {
        console.log(this.username + "唱一只小蜜蜂");
      };
      Person.prototype.say = function () {
        console.log(this.username + "你好呀");
      };
      // 构造函数 子元素
      function Son(name, age, height, gender) {
        Person.call(this, name, age, height);
        this.gender = gender;
      }

      // 通过new的方式创建实例
      // const p1 = new Person("大头爸爸", 32, 160);
      const s1 = new Son("小头儿子", 11, 140);
      // 分别打印输出p1,s1
      // console.log(p1);
      // console.log(s1);


      // 原型函数 继承方法
      Son.prototype.sing = Person.prototype.sing
      Son.prototype.say = Person.prototype.say
      // s1 调用 输出
        s1.sing();
        s1.say();
      

bind ,call ,apply的区别

call ,apply,bind 修改this的指向

call,apply 直接返回调用的结果,而bind 不会直接调用函数,而是返回一个新的函数,需要我们主动调用新的函数,

 	const father = {
        name: "灰太狼",
        skill() {
          console.log(this.name + "会抓羊");
        },
      };
      const son = {
        name: "小灰灰",
      };

      // call 方式来修改this的指向
      father.skill.call(son); //this 指向son

      // apply 方式来修改this的指向
      father.skill.apply(son); //this 指向son

      // bind 方式来修改this指向
     // bind 不会直接调用skill函数 而是 返回一个新的函数
      // 需要我们主动的调用新的函数- 调用skill()
     const func =  father.skill.bind(son)
     func()


call ,apply,bind 传参区别

call传递参数 :obj.skill.call(person,参数1,参数2)

apply传递参数:obj.skill.apply(person,[参数1,参数2])

bind 传递参数 : func(参数1,参数2)

 	const father = {
        name: "灰太狼",
        skill(a,b) {
          console.log(this.name + " " + a + " "  + b);
        },
      };
      const son = {
        name: "小灰灰",
      };
      // call传递参数
    father.skill.call(son,1,2)

    // apply传递参数
    father.skill.apply(son,[1,2])

      // bind 传递参数
     const func =  father.skill.bind(son)
     func(1,2)

ES6-class

目前浏览器 支持的js代码版本,主要支持es5 (for if while函数,forEach)版本,新的语法 es6 (提供了更加简单强大的代码更能力) 提高我们的开发效率

Es5的面向对象

  1. es5 写一个 构造函数 首字母是大写
 <script>
      // 
      // 当我们new 一个 对象的时候 Person 代码会被执行
      function Person(name) {
        // console.log("开始创建对象啦");
        this.name = name;
      }

      // 定义行为 引出 原型
      Person.prototype.say = function () {
        console.log('say方法被调用啦 ' + this.name);
      };

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

      console.log(p1.say === p2.say);   //输出true
    </script>

Es6的面向对象

  1. es6 面向对象 引出新的语法 类 class
    <script>
      class Person {
        // 方法 constructor 在es6 构造函数
        // constructor 会在 new Person的时候触发
        constructor(name) {
          // console.log("开始创建对象啦");
          this.name = name;
        }

        // 直接写行为
        say() {
          console.log("say方法被调用啦 " + this.name);
        }
      }
      // 一样new一个对象
      const p1 = new Person("悟空1");
      const p2 = new Person("悟空2");

      console.log(p1.say === p2.say); //输出true

    </script>

Es5继承

Es5继承 => 借调( call )

<script>
      // 爸爸 person name属性
      function Person(name) {
        this.name = name;
      }
      // 爸爸 person say行为
      Person.prototype.say = function () {
        console.log("say方法我调用啦 " + this.name);
      };
      // 爸爸 person fly行为
      Person.prototype.fly = function () {
        console.log("父亲 起飞");
      };

      // 儿子 student name属性,color属性
      function Student(name, color) {
        Person.call(this, name); // 继承爸爸name属性
        this.color = color;
      }
      //  儿子继承爸爸 say行为
      Student.prototype.say = Person.prototype.say;
      //  儿子继承爸爸 fly行为
      Student.prototype.fly = Person.prototype.fly;

      // new一个对象
      const s1 = new Student("学生", "red");
      //  儿子 调用 say方法
      s1.say();
    </script>

Es6继承

Es6继承 ---- extends

注意点:

  1. 如果你写了 extends 而且还写了 constructor 那你必须要在 constructor 调用了方法 super( );

    (super 表示可以继承父亲的属性)

  2. 如果你只写了 extends 但是你没有写constructor 不需要管super

  3. 父类的构造函数 super :子类有构造方法且使用this前,必须使用super()。不然会报错

     Must call super constructor in derived class before accessing 'this' or returning from derived constructor
     译文:必须调用超构造函数在派生类访问'this'或从派生构造函数返回之前
    
  4. 方法重写 override:子类方法覆盖父类,super.父类方法()

    class Person {
      // 构造方法
      constructor(name) {
        // 属性
        this.name = name;
      }
      // 方法
      say() {
        console.log(this.name);
      }
    }
	// 继承
 // extends 直接就实现了继承父亲的方法
    class Student extends Person{
      constructor(name,height){
        // console.log(this);			// 语法错误:必须先调用super()才能使用this
        super(name);	 // 父亲的构造函数 =es5   Person.call(this,name);
        this.height=height;
      }
    }

    const s1=new Student("八神",180);
    s1.say();							// 八神

	class Saler extends Person{
        constructor(name,age){
            super(name);
            this.age = age;
        }
        // 覆盖(重写)
        say(){
            // 访问父类方法
            super.say();				// 马云
            console.log(this.age);
        }
    }

	const s2 = new Saler('马云',50);
	s2.say();							// 50

Es6属性和方法的写法

属性写法有两种

  1. 可以写在 大括号内

     class Person {
            color = "yellow";
            height = 180;
            weight = 200;
            constructor(name) {
              this.name = name;
            }
       
            say = () => {
              // 箭头函数中的this , 绝大部分指向  window
              // 例外 用在 es6的class 充当 方法  this 指向 p1 实例
              console.log("say 方法被调用了 " + this.name);
            };
          }
          const p1 = new Person("悟空");
          p1.say();
          console.log(p1);
        </script>
    
  2. 直接在构造函数内 constructor this.name=name

     <script>
          class Person {
            constructor(name) {
              this.name = name;
              this.color = 'yellow';
              this.height = 180;
              this.weight = 200;
            }
            say = () => {
              // 箭头函数中的this , 绝大部分指向  window
              // 例外 用在 es6的class 充当 方法  this 指向 p1 实例
              console.log("say 方法被调用了 " + this.name);
            };
          }
          const p1 = new Person("悟空");
          p1.say();
          console.log(p1);
        </script>
    

方法写法有三种

推荐写法一,性能最好,同一个内存

		// 写法一:方法简写
         say() {
         console.log('say 方法被调用了 ' + this.name);
        }
        // 写法二:普通函数
        say = function () {
        console.log('say 方法被调用了 ' + this.name);
         };
        // // 写法三 :箭头函数
        say = () => {
          // 箭头函数中的this , 绝大部分指向  window
          // 例外 用在 es6的class 充当 方法  this 指向 p1 实例
          console.log("say 方法被调用了 " + this.name);
        };

函数参数默认值

定义函数的同时可以给形参一个默认值

函数参数默认值

  • ​ 如果没有给我传递参数,那我就输出默认值

  • ​ 如果你给我传递了参数,那我就输出你的参数


    function show(msg = '你好',str = '你我都好') {
      console.log(msg,str);
    }
    // 调用函数
    show()  //输出 你好,你我都好
    show('大家好')    //输出 大家好,你我都好
    show('大家好','世界美好') // 输出大家好,世界美好

对象简写

在定义对象的时候,如果属性名和变量名一致,可以实现简写

属性简写

    以前属性的书写方式
      const obj = {
        username:'小明'
      }
      
      es6方式 如果变量的名字和对象的属性的名字 一致的话,对象可以简写 作用创建对象更方便
      const username = "小明";
      const age = 18;
      const say = function () {};
      const obj = {
        username,
        age,
        say,
      };
      console.log(obj);

方法简写

//以前常规写法
      const obj1 = {
      say:function(){
       console.log('say');
        }

        // es6关于方法简写
        show(){
          console.log('show');
        }
       
      };
      obj1.say()
	  obj1.show()

解构

提供更加方便获取数组中的元素或者对象中属性的写法

数组解构

	const [a,b,c] = ['悟空','八戒','唐僧']
    console.log(a,b,c); //输出悟空 八戒 唐僧

元素交互顺序

 	  let num1 = 100;
      let num2 = 200;
      [num2,num1] = [num1,num2];
      console.log(num1,num2); //输出200,100

对象解构(重点)


 	   const obj = {
        name: "小明",
        age: 18,
        sex: "男",
      };
      const { name, age, sex } = obj;
      console.log(name,age,sex)  //输出小明 18 男

解构+数组默认值

没有参数又没有默认值就输出undefined

  const arr = [1];
  const [a,b ] = arr; //a = 1 如果b没有参数就输出b=undefined

没有参数,就使用默认值,有参数,就使用参数

// b = 2 默认值
      const [a, b = 2] = [1]; //没有参数
      console.log(a, b); //输出 a =1  b = 2

     
      const [a1, b1 = 2] = [1,100]; //有参数
      console.log(a1,b1);//输出 a1 =1  b1 = 100

解构+对象默认值

和数组默认值用法一样

     const obj = {
        username: 100,
        height: 500,
      };
      const { username, height = 200 } = obj;
      console.log(username, height); //输出100,500

拓展运算符||剩余运算符

剩余思想(获取剩下的数据)

数组中获取

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

      console.log(c);// 输出[3,4,5,6,7]
      console.log(c); // 输出 [3]
      console.log(c); // 输出 []

也可以利用... 将伪数组转成数组

对象中获取

      const { a, ...c } = { a: 1, b: 2, c: 3 };
      const { a1,b1,c1 ,...d1 } = { a1: 1, b1: 2, c1: 3 };
      console.log(c);// 输出 {b:2,c:3}
      console.log(d1); // 输出 {}

函数中获取

用在函数的形参中,输出数组的格式

	 calc(1, 2, 3);
      function calc(...args) {
        // args= 数组 装载这所有传给calc的参数
        console.log(args); //输出 args = [1,2,3]
      }
     

应用场景:计算数据求和

 	function calc(...args) {
        let sum = 0;
        args.forEach((value) => (sum += value));
        console.log(sum); 
      }
      calc(1, 2); //  输出3
      calc(1, 2, 3); // 输出6
      calc(1, 2, 3, 4); // 输出10

拓展思想

数组中获取

	 const arr = ['a', 'b', 'c'];
      // 在数组的后面 新增一个 元素 'd'
      const newArr=[...arr,'d'];  // 输出['a', 'b', 'c','d']
	   console.log(newArr);

   // 在数组的前面 新增一个属性 w
      const newArr1 = ['w', ...arr];
      console.log(newArr1); // 输出['w','a', 'b', 'c']

对象中获取

 const obj = {
        username: '悟空',
        height: 200,
      };
      const newObj1 = { ...obj, color: 'yellow' }; // 给newObj 开辟新的内存空间
      newObj1.username = '八戒';
      newObj1.weight = 100;
      console.log(newObj1); //输出{username: '八戒', height: 200, color: 'yellow', weight: 100}

数组去重

方式1:some方法,只要有一个符合条件就返回true

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

方式2:假设定义法,定一个变量表示有没有重复的数据,对数组中的每一个元素和输入框的值循环做比较,如果找到重复就跳出循环

	const input = document.querySelector('input');
      const ul = document.querySelector('ul');
      const arr = ['a', 'b'];
      render();

      input.addEventListener('keydown', function (event) {
        if (event.key === 'Enter') {
          // 假设它 没有重复
          let isHas = false;
          for (let index = 0; index < arr.length; index++) {
            // 如果找到了,设置 isHas=true 同时 打断循环
            if (arr[index] === this.value) {
              // 找到重复了
              isHas = true;
              break;
            }
          }
          // 判断数据有没有重复
          if (isHas) {
            // 有重复
            console.log('有重复');
          } else {
            // 没有重复 添加
            arr.push(this.value);
            render();
          }
        }
      });

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

方式3:filter方法,过滤出和当前输入框不相等的数据组成新数组,然后旧数组等于新数组,最后再添加过滤好的新数组

 const input = document.querySelector('input');
      const ul = document.querySelector('ul');
      let arr = ['a', 'b'];
      render();

      input.addEventListener('keydown', function (event) {
        if (event.key === 'Enter') {
        // 过滤出不包含 当前输入框的值的数组
          const newArr = arr.filter((value) => value !== this.value);
          console.log(newArr)
          // debugger
          // 让我们的旧的数组 等于你过滤后的数组
          arr = newArr;
          arr.push(this.value);
          render();
        }
      });

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

方式4:假设定义法,利用数组删除方法,先删除相同的再添加

 	 const input = document.querySelector('input');
      const ul = document.querySelector('ul');
      let arr = ['a', 'b'];
      render();

      input.addEventListener('keydown', function (event) {
        if (event.key === 'Enter') {
         let i = -1; // -1 表示没有找到
          for (let index = 0; index < arr.length; index++) {
            if (arr[index] === this.value) {
              i=index;
              break;
            }
          }

          // 判断 i 等于-1 表示没有相同,直接添加
          //  i 不等于-1 表示有相同,先执行删除 再添加
          if(i===-1){
            arr.push(this.value);
          }else{
            // 找到相同
            arr.splice(i,1);
            arr.push(this.value);
          }
          render();
        }
      });

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

方式5:set方法去重

基础知识

set 是一个对象,不是数组

使用set 数组去重,需要先考虑把旧数组转成对象,最后再将对象转成数组

数组转对象方法 :new Set(beforeArr)

去重处理 : set.add( 元素)

对象转数组方法:const arr = [...set]

去重案例

  	  const input = document.querySelector("input");
      const ul = document.querySelector("ul");
      let arr = ["a", "b"];
      render();
      input.addEventListener("keydown", function (event) {
        if (event.key === "Enter") {
          // 去重处理
          const set = new Set(arr); //1.数组转对象
          set.add(this.value); //2.去重处理
          arr = [...set]; //3.对象转数组
          render();
          input.value = "";
        }
      });

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

函数的四种调用模式

函数调用模式

如果一个函数不是一个对象的属性时,就是被当做一个函数来进行调用的。此时this指向了window

function fn(){
  console.log(this);// 指向window 
}
fn();

方法调用模式

当一个函数被保存为对象的一个属性时,我们称之为一个方法。当一个方法被调用时,this被绑定到当前对象

const obj = {
  sayHi:function(){
    console.log(this);//在方法调用模式中,this指向调用当前方法的对象。
  }
}
obj.sayHi();

构造函数调用模式

如果函数是通过new关键字进行调用的,此时this被绑定到创建出来的新对象上。

   function Person() {
        this.name = '悟空';
      }
      Person.prototype.say = function () {
        console.log(this); //this指向被实例化,p1
      };
      const p1 = new Person();
      p1.say(); 

方法借用模式

也叫上下文模式,分为 apply 与 call

call

call方法可以调用一个函数,并且可以指定这个函数的this指向

call应用:将伪数组转成数组

let newArr = Array.protype.slice.call(伪数组)

apply

就是apply()方法接受的是一个包含多个参数的数组。而call()方法接受的是若干个参数的列表

apply应用:1.简化log方法

bind方法

**bind()**方法创建一个新的函数, 可以绑定新的函数的this指向

const father = {
    name: "灰太狼",
    skill() {
      console.log(this.name + "会抓羊");
    },
  };
  const son = {
    name: "小灰灰",
  };

  // call 方式来修改this的指向
  father.skill.call(son); //this 指向son

  // apply 方式来修改this的指向
  father.skill.apply(son); //this 指向son

  // bind 方式来修改this指向
 // bind 不会直接调用skill函数 而是 返回一个新的函数
  // 需要我们主动的调用新的函数- 调用skill()
 const func =  father.skill.bind(son)
 func()
     
     
     
     
     

js数组装字符串(3种方法)和字符串转数组(2种方法)

数组转字符串

JavaScript 允许数组与字符串之间相互转换。其中 Array 方法对象定义了 3 个方法,可以把数组转换为字符串,如表所示。

image-20220504190403566

1:join()方法用于把数组中的所有元素放入一个字符串

元素是通过指定的分隔符进行分隔的

image-20220504190458351

// join(',')
const a= ["00", "01", "02", "03", "04"]
const b=  a.join(',')      
console.log(b)
console.log( typeof b)
//打印结果  00,01,02,03,04

或者

// join('-')
const a= ["00", "01", "02", "03", "04"]
const b=  a.join('-')      
console.log(b)
console.log( typeof b)
//打印结果  00-01-02-03-04

或者
// join('!')
const a= ["00", "01", "02", "03", "04"]
const b=  a.join('!')      
console.log(b)
console.log( typeof b)
//打印结果 00!01!02!03!04

2:toString()方法可把一个逻辑值转换为字符串,并返回结果

const a= ["00", "01", "02", "03", "04"]
const c = a.toString();  //把数组转换为字符串
console.log(c)
console.log(typeof c);  //返回字符串string,说明是字符串类型
//打印结果  00,01,02,03,04

toString()方法不可以指定分隔符,但是我们可以通过replace()方法指定替换

const a= ["00", "01", "02", "03", "04"]
const f = a.toString().replace(/,/gi,'-') //	正则表达式/,/gi,'-'
console.log(f)
//打印结果:00-01-02-03-04

3:toLocaleString()

把数组转换成本地约定的字符串

const a= ["00", "01", "02", "03", "04"]
const e = a.toLocaleString();  
console.log(e)
console.log(typeof e);  
//打印结果:00,01,02,03,04

字符串转数组

image-20220504190938380

1:split() 方法用于把一个字符串分割成字符串数组

const arr = 'aa,bb,cc,dd'
const newStr = arr.split()
console.log(newStr)
// 打印结果: ["aa,bb,cc,dd"]

2:es6里面的扩展运算符

const arr = 'aa,bb,cc,dd'
const newStr = [...arr]
console.log(newStr) 
//打印结果 ["a", "a", ",", "b", "b", ",", "c", "c", ",", "d", "d"]