JS高级语法————黑马课程

发布于:2022-12-02 ⋅ 阅读:(973) ⋅ 点赞:(0)

目录

1.面向对象

2.ES6中的类和对象(抽象 和 具体)

 2.1 创建类

 2.2 类constructor 构造函数

 3.类的继承

 3.1super 关键字

继承属性和方法的查找原则(就近原则)

4.使用类的2个注意点

5.类里面this的指向问题

6.面向对象案例 tab栏 动态添加标签页

 6.构造函数和原型

 6.1 实例成员和静态成员

6.2 构造函数存在浪费内存问题

 6.2.1 构造函数的原型   prototype

 方法的查找规则:

6.2.2 对象原型  _proto_     

 对象原型 等价于 构造函数原型对象   实例对象._proto_ === 构造函数.prototype

6.2.3构造函数 constructor

 6.2.4  构造函数,实例,原型对象三者之间的关系

 6.2.5  原型链

 6.2.6 JavaScript的成员查找机制(规则)

6.2.7  原型对象中this的指向

6.2.8 原型对象的一个应用————扩展内置对象

7.继承方法

7.1  利用ES6 类继承

class son extend Father {  constructor(){}  } 

7.2 组合继承

7.2.1  借用父构造函数实现继承

call(调用者,参数1,参数2,...)

 Father.call()  改变Father的this指向

 7.2.2 借用原型对象继承   

利用父亲的实例的_proto_属性访问, 别忘了利用construcor指回原来的构造函数

 8.类的本质

9.ES5 新增方法 

​编辑

9.1 ES5新增  数组的方法

 9.1.1 arr.forEach( function (value, index, array){})     

 9.1.2 filter

 9.1.3  some()

9.2 ES5新增  字符串的方法

trim方法去除字符串两端的空格

 9.3 ES5新增  对象方法

9.3.1Object.defineProperty方法     vue会用到

 9.3.2  Object.keys()     

 10.函数的进阶

10.1 函数定义方式  三种

 10.2  函数的调用方式

 10.3  函数内部的this指向

 fn.call(调用者,参数1,参数2...)

  fn.apply(调用者,[参数])             参数必须包含在数组(伪数组)里

 fn.bind(把this指向谁,参数1,参数2,...)        只改变this指向,不调用!     

call apply  bind 总结

 10.4 JS当中的严格模式  IE10+

 开启严格模式

1.为脚本开启严格模式

 2.为函数开启严格模式

 严格模式下的语法规范

 10.5  高阶函数,

 10.6  闭包closure-------内部函数访问外部函数的局部变量

闭包产生条件: 

实现闭包的两种方式:

闭包的主要作用:延长了变量的作用范围和生命周期

 闭包的应用———解决变量泄露的问题(循环,定时器等)

闭包考题

 闭包总结

 10.7 递归  (函数内部自己调用自己)    求数学题!

10.8 浅拷贝和深拷贝

10.8.1 浅拷贝     只拷贝基本数据或复杂数据的地址

 10.8.2  深拷贝             里层利用递归实现深层拷贝

 11. 正则表达式         多用于表单的验证

 边界符

 字符类

 量词符

 量词重复某个模式出现的次数

 括号总结

 预定义类

 正则表达式中的替换

 12.ES6   

12.1 let关键字     

12.2 const关键字   声明常量

 12.3  解构赋值

12.3.1数组解构

 12.3.2 对象解构

 12.4 箭头函数

12.5 剩余参数

 12.6 剩余参数和解构配合使用

 13.  ES6的新增内置对象 

13.1  数组的新增方法

13.1.2 扩展运算符 ————相当于把数组的中括号去掉

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

 13.1.4  实例的方法  find()

 13.1.5 实例方法 : findIndex()

13.1.6  实例方法:includes()

13.2   String的扩展方法

13.2.1 模板字符串

 13.2.2 实例方法:startWith() 和 endWith()

 13.2.3  实例方法:repeat()

 13.3 Set数据结构   数组去重原理


1.面向对象

面向对象相当于盖浇饭, 需要什么口味的,就浇什么口味的汁(适合多人维护)  

面向过程就是做一份蛋炒饭

2.ES6中的类和对象(抽象 和 具体)

泛指某一大类 和 特指某一个

 2.1 创建类

 2.2 类constructor 构造函数

类添加方法

  •  类里面所有函数不需要加function
  • 类里面多个函数或方法之间不需要添加逗号分隔

 3.类的继承

子承父业,儿子可以继承父亲的一些属性和方法

但子类和父类都拥有各自的constructor  父类里方法的参数用的是父类condtructor的,子类想给父类的方法传参调用,必须要用super关键字,即调用父类的构造函数

原因是this指向不同

子类的构造函数中的 this指向 子类 构造函数创建的那个实例

父类的构造函数中的 this指向 父类 构造函数创建的那个实例

所以要调用父类里的函数(有参数的)必须先在子类构造函数里先调用父类的构造函数super,

且super必须放在子类this之前

 3.1super 关键字

子类不仅可以调用父类的构造函数,也可以调用父类的普通函数

super相当于ES5 的call(), apply()改变this指向

继承属性和方法的查找原则(就近原则)

  1. 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
  2. 如果子类没有,就去查找父类有没有这个方法,有就执行(就近原则)

4.使用类的2个注意点

  1. ES6里面没有变量提升,所以必须先定义类,才能通过类实例化对象
  2. 类里面的共有属性和方法必须通过加this使用
  3. 在类中所有的方法都自动定义在prototype的属性上 

5.类里面this的指向问题

this开辟了一个新空间,表示在哪里添加变量。

谁调用就指向谁, 方法this指向不是实例的时候又想要调用实例的属性,就用全局that调用

 <button>我是谁的按钮</button>
    <script>
      let that = null
      class Star {
        constructor(uname, age) {
            //以下这些数据都添加在实例里面了  方法不能直接使用 必须要用this指明使用 
          that = this  //将实例地址赋值给that
          this.uname = uname;
          this.age = age;
          this.btn = document.querySelector('button') //给实例对象添加获取一个按钮元素
          this.btn.addEventListener('click', this.sing)
        }
        sing() {
        //   console.log(this.uname);undefined  //this指向调用者 ,这里是btn调用 而btn没有uname
          console.log(that.uname);  //如果想用实例对象里的 就要用全局that保存this 
        }
        dance() {
          console.log(this.age);
        }
      }
      let ldh = new Star("刘德华", 18);  //刘德华拥有 大家都可以使用里面的方法和属性
      ldh.dance() //实例对象调用


    </script>

6.面向对象案例 tab栏 动态添加标签页

  1. 先创建一个tab 类 (最大的父盒子)
  2. 类里面 获取所有要用的子元素,初始化(给所有子元素绑定点击事件)
  3. 写上所有功能需求的函数
  4. 补充完善里面的每一个功能函数

new Tab('#tab') //传对象

 

 

 2.

 6.构造函数和原型

在ES6之前是没有类的概念的  是通过构造函数创造一个对象

 

 6.1 实例成员和静态成员

  • 实例成员是通过this添加的,
  • 静态成员是直接给构造函数本身添加的Star.sex = '男'
  • 实例成员只能通过实例化的对象访问
  • 静态成员只能通过构造函数来访问

6.2 构造函数存在浪费内存问题

ldh.sing=== zxy.sing   //false  比较的是两个sing函数的地址 地址不同

所以一些不变的方法(没有参数)可以放到原型对象上供大家使用,减少内存浪费

 6.2.1 构造函数的原型   prototype

  1. 原型是什么?   一个对象,我们称为prototype为原型对象
  2. 原型的作用?    共享方法,避免开辟不必要的内存空间。
  3. 一般情况下,我们的公共属性定义到构造函数里面,公共的方法我们放到原型对象身上。

  实例对象.sing() 可以调用

 

 方法的查找规则:

首先看实例对象上是否有sing方法,如果有就执行这个对象上的sing方法, 

如果没有,因为有_proto_的存在,就去构造函数的原型对象prototype身上查找sing这个方法

6.2.2 对象原型  _proto_     

只要是对象,它就会有_proto_原型

 这个属性开发中并不能直接使用, 只是在内部给对象的查找提供了一个方向

 

 对象原型 等价于 构造函数原型对象   实例对象._proto_ === 构造函数.prototype

6.2.3构造函数 constructor

对象原型即构造函数原型对象里面都有一个属性: constructor属性   指回构造函数本身

 6.2.4  构造函数,实例,原型对象三者之间的关系

 6.2.5  原型链

  1. 只要是对象就一定有_proto_属性,即原型,而原型是一个对象
  2. 每个函数都有一个prototype属性,函数通过prototype属性去原型链查找
  3. 对象通过原型链这条线路查找 (内部查找)
  4. ldh实例对象的原型是一个对象,而这个对象是Object的实例对象  

 

  1.  是函数必定有prototype属性, 有prototype属性,必定有原型链即有爸爸—爸爸的爸爸—null。
  2. 是对象必定有_proto_属性。[[prototype]]是_proto_的书面写法,不同的浏览器输出写法不同。
  3. 构造函数和普通函数既是函数,又是对象,所以他们两个属性都有,只是普通函数的这两个属性都指向同一个对象,
  4. 而构造函数是普通函数的实例,他的原型指向普通函数的原型对象。

 6.2.6 JavaScript的成员查找机制(规则)

实例对象——爸爸——————————爸爸的爸爸——————null

内部查找是根据原型自动依次往上查找,即原型链

 我无论在那一层添加了属性,它都能根据原型链找到这个属性

实例对象访问的东西要么来自本身,要么来自构造函数,要么来自原型链

 外面想访问函数里的this,就需要用一个全局变量that将this存储起来

6.2.7  原型对象中this的指向

不管是构造函数里的this还是原型对象里的this,指向的都是调用者,也就是实例对象

6.2.8 原型对象的一个应用————扩展内置对象

通过原型对象,对原来的内置对象进行扩展自定义的方法。比如给数组添加自定义求偶数和功能

7.继承方法

7.1  利用ES6 类继承

class son extend Father {  constructor(){}  } 

类中所有的方法都定义在prototype的属性上,所以类的继承 也就同时继承了  构造函数+原型对象

7.2 组合继承

ES6之前没有extends继承  我们可以通过构造函数+ 原型对象 模拟实现继承, 被成为 组合继承,

,需要两步,较为繁琐。

7.2.1  借用父构造函数实现继承

call(调用者,参数1,参数2,...)

 Father.call()  改变Father的this指向

 7.2.2 借用原型对象继承   

利用父亲的实例的_proto_属性访问, 别忘了利用construcor指回原来的构造函数

 8.类的本质

class Star{}       

类的本质是一个函数, 是构造函数的另一种写法,构造函数有的它都有。

ES6 之前通过 构造函数+原型 实现 面向对象 编程

ES6 通过 类  实现 面向对象 编程  是构造函数的语法糖

9.ES5 新增方法 

9.1 ES5新增  数组的方法

 

 9.1.1 arr.forEach( function (value, index, array){})     

 回调函数的三个参数:每一个数组元素   下标    数组名     

相当于增强版的for循环 也就是 v-for (item,index)in  array

 

 9.1.2 filter

 筛选出符合条件的value放入新数组中

 value >= 20 得到的是布尔值,返回结果为true的成员组成新数组

 9.1.3  some()

 是否有返回条件的数,有返回true

 //false

 

 

 查询符合条件的商品思想:fliter

  1.  封装一个遍历数组生成表格的函数fn,只需要传一个数组进去遍历就可以了。
  2. 先调用fn遍历一个数组的全部数据显示出来,
  3. 利用filter筛选选出符合条件的数存进新数组,清除所有数组后再调用fn遍历新数组

查询商品名 思想:some (找到第一个立马跳出循环) 适合用于查找数组中唯一的一个元素

  • if 符合条件 就将这个 value push到新数组 返回true跳出some循环
  • 然后利用fn遍历新数组
  • forEach和 filter中的return不会跳出循环 ,会把所有元素遍历完,效率低

9.2 ES5新增  字符串的方法

trim方法去除字符串两端的空格

会删除两边的 不会删除中间的空格

应用场景:表单输入为空格时 可以视为用户未输入内容

 9.3 ES5新增  对象方法

9.3.1Object.defineProperty方法     vue会用到

  

默认不可枚举,不可删除不可重新设置参数的值true或false,不可重写

delete obj.address ×

 

 9.3.2  Object.keys()     

  获取对象的所有属性名

 

 10.函数的进阶

10.1 函数定义方式  三种

 

 10.2  函数的调用方式

 10.3  函数内部的this指向

另外 call  apply  bind 可以改变this指向  

 fn.call(调用者,参数1,参数2...)

 主要应用:

继承父亲构造函数 但没继承原型  还是ES6的类好用

  fn.apply(调用者,[参数])             参数必须包含在数组(伪数组)里

主要应用:利用数学内置对象求最大最小值  不过似乎用 Math.max(...arr)更好

Math.max.apply (Math,arr)

 fn.bind(把this指向谁,参数1,参数2,...)        只改变this指向,不调用!     

返回的是原函数改变this之后的新函数

主要应用: 如果函数不需要立即调用,但又想改变这个函数内部的this指向此时用bind

 

 另一个应用场景:

把构造器中的this作为参数传给方法使用 

方法里的this还是可以指向想要的调用者

调用者是每一个li

call apply  bind 总结

 10.4 JS当中的严格模式  IE10+

 开启严格模式

1.为脚本开启严格模式

 

 2.为函数开启严格模式

 严格模式下的语法规范

    1. 变量规定

  • 变量必须先声明,在使用  (正常模式不声明则默认为全局变量)
  • 不能删除已经声明的变量    delete x;语法是错误的

    2. 严格模式下,this的指向问题

  • 全局作用域下的this指向undefined      !!   (正常模式下是window)
  •  构造函数不加new调用,this会报错

  •    定时器this还是指向window

     3.函数变化

  •      函数不能有重名参数                         function (a,a){} ×
  • 函数必须声明在顶层,且不允许在非函数的代码块声明函数              //  为了与新版本接轨

10.5  高阶函数,

 callback&&callback()意思是 若callback存在就执行callback()

1.回调函数是最后执行的,等函数里所有代码执行完之后才执行回调函数

2.闭包就是典型的高阶函数,将一个函数作为返回值。

 10.6  闭包closure-------内部函数访问外部函数的局部变量

重点:被访问的函数才是闭包函数

  • 闭包产生条件: 

  1. 内部函数
  2. 访问外部函数的局部变量

在JS中闭包和异步 是两大难点

  • 实现闭包的两种方式:

1.内部函数访问外部函数的局部变量

2.外面的作用域访问函数内部的局部变量  (这种方式需要return一个函数出去)

 

  • 闭包的主要作用:延长了变量的作用范围和生命周期

  •  闭包的应用———解决变量泄露的问题(循环,定时器等)

异步任务三种情况:

  1. 定时器中的回调函数
  2. DOM事件中的回调函数
  3. ajax中的回调函数

异步任务只有触发了,才会执行  (如3秒之后,点击之后)

而for循环属于同步任务会立马执行,i已经加加完了才执行异步任务

而这时可以使用小闭包(立即执行函数)来存i值  或者for用let 声明 i

 应用1:点击li打印当前索引

  这里不适合使用闭包

 应用2: 3秒之后打印li的内容

 应用2:计算打车价格

    <!-- 面向对象:闭包应用  计算打车价格
    用户输入公里数 计算打车价格 起步价13(3公里内) 之后每多一公里加5元  
    堵车的话另外收加10元   -->
      
    <script>
      // function fn (){}
      // fn()  我写一个函数需要调用才执行
      // 但立即执行函数不需要调用
      var car = (function () {     //这个匿名函数就是闭包
        var start = 13; //起步价
        var total = 0; //总价
        // 功能1:按公里计费
        return {
          // 立即执行函数返回一个装多个功能函数的对象
        //   外部调用就能使用函数内的变量了
          getTotal: function (n) {   //用户传进公里数   
            if (n <= 3) {
              total = start; //内部函数使用了外部变量  闭包
            } else {
              total = start + (n - 3) * 5;
            }
            return total;
          },
          // 功能2: 拥堵之后的费用
          yd: function (flag) {
            return flag ? total + 10 : total;
          },
        };
      })();
      //巧妙之处就在于:立即执行函数 无需小括号调用 否则普通函数需要car().yd()才能调用
      car.getTotal(5); //car返回的是一个对象,直接点调用里面的函数
      car.yd()
    </script>
  • 闭包考题

思考题1:

思考题2:

  •  闭包总结

 10.7 递归  (函数内部自己调用自己)    求数学题!

 

 超出了栈的最大容量,会报错

 

 10.7.1 利用递归求阶乘

核心思路:

不管是求1~n之间的阶乘,还是求1~n之间的累加和,都是用 前一项n ×或+  后一项,只不过后一项是通过递归不断调用求得fn(n-1)

我×我自己减1  我再×我自己减1....每一个我都是减一后的我 直到我符合条件终止递归

 10.7.2   利用递归求斐波那契数列    (每次调用返回的最终都是1累加起来的结果)

 10.7.3 利用递归遍历数据   !!(这里不需要终止条件,直接利用条件判断是否需要执行递归

 

  var data = [
        {
          id: 1,
          name: "家电",
          goods: [
            {
              id: 11,
              gname: "冰箱",
              goods: [{ id: 111, ggname: "海尔" }],
            },
            {
              id: 12,
              gname: "洗衣机",
            },
          ],
        },
        {
          id: 2,
          name: "服饰",
        },
      ];
      //   console.log(data);
      //   用forEach遍历数组里的每一项item
      function getId(arr, id) {
        var o = {};
        arr.forEach(function (item) {
          //第一层 有这个id的话就返回
          if (item.id === id) {
            // console.log(item);
            o = item;
          }
          //第一层没有的话就去第二层找
          //里面有goods这个数组且长度不为0
          else if (item.goods && item.goods.length > 0) {
            o = getId(item.goods, id);
            //得到的o只是return给了当前这个getId函数,最外层没有接受到o值,需要o接收
          }
        });
        return o; //把最终的值return出去使用
      }
      console.log(getId(data, 111));

10.8 浅拷贝和深拷贝

10.8.1 浅拷贝     只拷贝基本数据或复杂数据的地址

浅拷贝 拷贝复杂数据会影响源对象    其中一个变另一个也跟着变

新增  Object.assign(拷贝给谁,拷贝谁)

 

obj[k]里存的是地址  o[k]接收的也是地址 浅拷贝

 10.8.2  深拷贝             里层利用递归实现深层拷贝

 

最终都是转换成基本数据的拷贝

 11. 正则表达式         多用于表单的验证

 

 

 

 

 边界符

 字符类

[] 含有就行

[^ $]限定多选一 ,只能由其中一个   ^&一起精确匹配

[^]取反,不能含有里面的任何一个

 

 量词符

 量词重复某个模式出现的次数

 括号总结

网址里都很多小工具,包括正则表达式测试工具,验证工具里面有很多正则例子

 预定义类

表单验证

 

 

 验证的过程基本是一样的 ,可以封装成一个函数。

 正则表达式中的替换

 

 12.ES6   

let const声明的变量只能声明再使用

12.1 let关键字     

 

 

 全局i

块级作用域i

12.2 const关键字   声明常量

 

const声明的常量   若是 基本数据类型不可以更改值,若是复杂数据类型不可以更改地址,但里面的值可以更改;即复杂数据类型不可以重新被赋值。

 

 const声明的变量的值不可以发生变化,所以javascript引擎不需要实时监测值的变化,所以使用const效率更高,能使用const尽量使用const。

 12.3  解构赋值

12.3.1数组解构

中括号在等号左边代表解构

 12.3.2 对象解构

{}在左边代表解构   以下两种写法:

 

 12.4 箭头函数

参数只有一个的时候,小括号可以省略;

代码只有一句的时候,大括号和return可以省略。

 箭头函数没有this,箭头函数当中的this指向定义时候爸爸的this

对象不是函数,不生成作用域。

12.5 剩余参数

当实参个数大于形参个数的时候,对于普通函数来说可以使用arguments,

但由于箭头函数没有arguments,所以需要借助剩余参数...

 

 12.6 剩余参数和解构配合使用

 13.  ES6的新增内置对象 

13.1  数组的新增方法

13.1.2 扩展运算符 ————相当于把数组的中括号去掉

应用1:作为参数传递

 

 应用2:合并数组

arr1.push(参数1,参数2,....) 在数组尾部追加元素

 应用3

将伪数组(只有长度没有方法,有length属性)转换成真正的数组[ ]   ,就可调用数组的方法了

 方法1:

 

方法2:

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

 13.1.4  实例的方法  find()

 index没用到可以省略不写

 13.1.5 实例方法 : findIndex()

区分: some()方法返回的是布尔值

13.1.6  实例方法:includes()

 数组包含2吗?

13.2   String的扩展方法

13.2.1 模板字符串

   

模板字符串里的 变量或函数 要写在  ${ } 里面

 13.2.2 实例方法:startWith() 和 endWith()

 13.2.3  实例方法:repeat()

 13.3 Set数据结构   数组去重原理

Set相当于数组数据结构,但里面存储的没有重复的值

可以用...扩展符将其转换成数组     arr = [ ...s ]

jq的size相当于length

从Set结构中取值,需要用遍历

 

应用:搜索关键字   

 

 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到