WebAPI编程 - JavaScript网页编程(3)- 必掌握知识点 - #博学谷IT学习技术支持#

文章目录

(续)20. 常见网页特效案例

20.1 节流阀

  • 防止轮播图按钮连续点击造成播放过快

  • 节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发

  • 核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数

    var flag = true;
    if (flag) {
        flag = false;
        // 函数动画内容(执行一次的内容)
    }
    
    animate(..., ..., function() {
    	flag = true;
    })
    

20.2 返回顶部

  • 滚动窗口至文档中的特定位置
  • window.scroll(x, y)
    • 注意:x,y 不跟单位

(续)21. 移动端轮播图

21.1 触屏事件(touch)

  • 常见的触屏事件:

    触屏touch事件说明
    touchstart手指触摸到一个 DOM 元素时触发
    touchmove手指在一个 DOM 元素上滑动时触发
    touchend手指从一个 DOM 元素上移开时触发

21.2 触摸事件对象(TouchEvent)

触摸列表说明
touches正在触摸屏幕的所有手指的一个列表
targetTouches正在触摸当前 DOM 元素上的一个手指的一个列表
changedTouches手指状态发生了改变的列表,从无到有,从有到无变化
  • 当我们手指离开屏幕的时候,就没有了 touches 和 targetTouches 列表,但是会有 changedTouches
  • 因为平时我们都是给元素注册触摸事件,所以重点记住 targetTouches

21.3 移动端拖动元素

  1. touchstart、touchmove、touchend 可以实现拖动元素

  2. 但是拖动元素需要当前手指的坐标值,我们可以使用 targetTouches[0] 里面的 pageX 和 pageY

    注意:手指移动也会触发滚动屏幕所以这里要阻止默认的屏幕滚动 e.preventDefault();

补充:
1. 过渡完成事件 transitionend
2. classList 属性
  • classList 属性是 HTML5 新增的一个属性,返回元素的类名。但是 ie10 以上版本支持。

  • 该属性中用于在元素中添加,移除及切换 CSS 类。有以下方法

    • 添加类:element.classList.add('类名');

      • 在后面追加类名不会覆盖以前的类名,注意前面不需要加 .
    • 移除类:element.classList.remove('类名');

    • 切换类:element.classList.toggle('类名');

      • 有这个类就删除,没这个类就添加

21.4 click 延时解决方案

  • 移动端 click 事件会有 300ms 的延时,原因是移动端屏幕双击会缩放页面

  • 解决方案

    • 禁止缩放。浏览器禁用默认的双击缩放行为并且去掉 300ms 的点击延迟。

      <meta name="viewport" content="user-scalable=no">

    • 利用 touch 事件自己封装这个事件解决 300ms 延迟。

      • 原理就是:

        1. 当我们的手机触摸屏幕,记录当前触摸时间
        2. 当我们手指离开屏幕,用离开的时间减去触摸的时间
        3. 如果时间小于 150ms,并且没有滑动过屏幕,那么我们就定义为点击
        function tap(obj, callback) {
            var isMove = false;
           	var startTime = 0; // 记录触摸时候的时间变量
            obj.addEventListener('touchstart', function(e) {
                startTime = Date.now(); // 记录触摸事件
            });
            obj.addEventListener('touchmove', function(e) {
                isMove = true; // 看看是否有滑动,有滑动算拖拽,不算点击
            });
            obj.addEventListener('touchend', function(e) {
               if(!isMove && (Date.now() - startTime) < 150) { // 如果手指触摸和离开时间小于 150ms 算点击
                   callback && callback();	// 执行回调含函数
               } 
                isMove = false; // 取反 重置
                satrtTime = 0;
            });
        }
        // 调用
        tap(div, function() {
            // 执行代码
        })
        
    • 使用插件。fastclick 插件解决 300ms 延迟

(续)22. Swiper 插件的使用(移动端)

  • 中文官网网址: https://www.swiper.com.cn/
  • 使用方法
    • 引入插件相关文件
    • 按照规定语法使用
  • 其他移动端常见插件
    • superslide
    • iscroll

(续)23. 框架概述

  • 框架(大而全,一套解决方案):就是一套架构,它会基于自身的特点向用户提供一套较为完整的解决方案。框架的控制权在框架本身,使用者要按照框架所规定的某种规范进行开发。
  • 插件(小而专一,某个功能的解决方案):一般是为了解决某个问题而专门存在,其功能单一,并且比较小。
  • 前端常用的框架有 Bootstrap、Vue、Angular、React 等。既能开发 PC 端,也能开发移动端。
  • Bootstrap框架的基本使用
    • 引入js文件时,先引入 jquery.js 再引入 bootstarp.js

(续)24. 本地存储

24.1 本地存储特性

  1. 数据存储再用户浏览器中
  2. 设置、读取方便、甚至页面刷新不丢失数据
  3. 容量较大,sessionStorage 约 5M,localStorage 约 20M
  4. 只能存储字符串,可以将对象 JSON.stringify() 编码后存储

24.2 window.sessionStorage

  1. 生命周期为关闭浏览器窗口
  2. 在同一个窗口(页面)下数据可以共享
  3. 以键值对的形式存储使用
  • 存储数据:

    sessionStorage.setItem(key, value)

  • 获取数据

    sessionStorage.getItem(key)

  • 删除数据

    sessionStorage.removeItem(key)

  • 删除所有数据

    sessionStorage.clear

24.3 localStorage

  1. 生命周期永久生效,除非手动删除否则关闭页面也存在
  2. 可以多窗口(页面)共享(同一浏览器可以共享)
  3. 以键值对的形式存储使用
  • 存储数据:

    localStorage.setItem(key, value)

  • 获取数据

    localStorage.getItem(key)

  • 删除数据

    localStorage.removeItem(key)

  • 删除所有数据

    localStorage.clear

补充:change 事件 ——> 针对 checkbox 的事件

第六章 面向对象编程(JS 高级)

1. 面向对象编程介绍

1.1 两大编程思想

  • 面向过程(POP):就是分析处解决问题所需要的步骤,然后用函数把这些步骤一步步实现,使用的时候再一个一个的依次调用即可。

    • 举例:把大象装进冰箱,有三步,按照分析好的每一步,按照步骤解决问题。
  • 面向对象(OOP):就是把事物分解成为一个个对象,然后由对象之间分工与合作。(以对象功能来划分问题,而不是步骤)

    • 举例:把大象装进冰箱,面向对象做法:
      • 先找出对象,并写出这些对象的功能:
        1. 大象对象
          • 进去
        2. 冰箱对象
          • 打开
          • 关闭
        3. 使用大象和冰箱的功能
    • 面向对象的特性:
      • 封装性
      • 继承性
      • 多态性
  • 两者对比:

    • 面向过程
      • 优点:性能比面向对象高,适合跟硬件联系很紧密的东西,例如单片机就采用的面向过程编程
      • 缺点:没有面向对象易维护、易复用、易扩展
    • 面向对象
      • 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
      • 缺点:性能比面向过程低

2. ES6 中的类和对象

2.1 对象

  • 在 JS 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象。
  • 对象是由属性和方法组成的:
    • 属性:事物的特征
    • 方法:事物的行为

2.2 类 class

  • 在 ES6 中新增加了类的概念,可以使用 class 关键字声明一个类,之后以这个类来实例化对象。
  • 抽象了对象的公共部分,它泛指某一大类
  • 对象特指某一个,通过类实例化一个具体的对象

2.3 创建类

class name {
    // class body
}

// 创建实例
var xx = new name();

注意:类必须使用 new 实例化对象

2.4 类 constructor 构造函数

  • constructor() 方法是类的构造函数(默认方法),用于传递参数,返回实例对象,通过 new 命令生成对象实例时,自动调用该方法。如果没有显示定义,类内部会自动给我们创建一个 constructor()

    class Star {
        // 共有属性放到 constructor 里面
        constructor(uname, age) {
            this.uname = uname;
            this.age = age;
        }
    }
    
    // 创建实例
    var xx = new name();
    var ldh = new Star('刘德华', 18);
    
  1. 通过 class 关键字创建类,类名我们习惯性定义首字母大写
  2. 类里面有个 constructor 函数,可以接收传递过来的参数,同时返回实例对象
  3. constructor 函数,只要 new 生成实例时,就会自动调用这个函数,如果我们不写这个函数,类也会自动生成这个函数
  4. 生成实例 new 不能省略

2.5 类添加方法

class Star {
    // 共有属性放到 constructor 里面
    constructor(uname) {
       this.uname = uname;
       this.age = age;
    }
    sing(song) {
        // console.log('我唱歌');
        console.log(this.uname + song);
    }
}

// 创建实例
var xx = new name();
var ldh = new Star('刘德华', 18);
ldh.sing('冰雨');
  1. 类里面所有的函数都不需要 function

  2. 多个函数方法之间不需要添加逗号分隔

3. 类的继承

3.1 语法格式(extends)

class Father {}

class Son extends Father {} // 子类继承父类

3.2 super 关键字

  • super 关键字用于访问和调用对象父类上的函数。可以调用父类的构造函数,也可以调用父类的普通函数

    • 调用父类的构造函数
    class Father {
        constructor(x, y) {
           this.uname = x;
           this.age = y;
        }
        sum() {
            console.log(this.x + this.y);
        }
    }
    
    class Son extends Father {
        constructor(x, y) {
            super(x, y); // 调用了父类中的构造函数
        }
    }
    var son = new Son(1, 2);
    son.sum();
    
    • 调用父类的普通函数
    class Father {
        say() {
            return '我是爸爸';
        }
    }
    
    class Son extends Father {
        say() {
            // console.log('我是儿子');
            console.log(super.say() + '的儿子');
            // super.say() 就是调用父类中的普通函数 say()
        }
    }
    var son = new Son();
    son.say();
    
    • 继承中的属性或者方法查找原则:(就近原则)

      • 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
      • 继承中,如果子类里面没有这个方法,就去父类里面查找,如果有,就执行父类这个方法
    • 注意:子类在构造函数中使用 super,必须放到 this 前面(必须先调用父类的构造方法,再使用子类构造方法)

3.3 三个注意点

  1. 在 ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象
  2. 类里面的共有属性和方法一定要加 this 使用
  3. 类里面的 this 指向问题
    1. constructor 里面的 this 指向实例对象,方法里面的 this 指向这个方法的调用者。

3.4 面向对象思想的tab栏切换

  • 补充(页面添加元素):

    • 以前的添加元素做法:动态创建元素 createElement,但是元素里面内容较多,需要 innerHTML 赋值,再 appendChild 追加到父元素里面。
    • 现在高级做法:利用 insertAdjacentHTML(position, text) 可以直接把字符串格式元素添加到父元素中。
      • position必须是[字符串]:‘beforebegin’(元素自身的前面)、‘afterbegin’(插入元素内部的第一个子节点之前)、‘beforeend’(插入元素内部的最后一个子节点之后)、‘afterend’(元素自身的后面)
  • 补充(双击禁止选中文字):

    • 双击事件是:ondblclick
    • window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();

4. 构造函数和原型

4.1 构造函数

  • JS 的构造函数可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数内部的 this 上添加。通过两种方式添加的成员,就分别称为静态成员和实例成员
    • 静态成员:在构造函数本上添加的成员称为静态成员,只能由构造函数本身来访问
    • 实例成员**(通过 this 添加)**:在构造函数内部创建的对象称为实例成员,只能由实例化的对象来访问

4.2 构造函数的问题

  • 构造函数方法很好用,但是存在浪费内存的问题
  • 简单数据类型直接赋值,复杂数据类型会在内存中开辟新的空间。所以每通过构造函数创建一个实例,调用其中的方法就会在内存中开辟新的空间。
  • 解决方法:构造函数原型

4.3 构造函数原型 prototype

  • 原型是:一个对象,我们也称 prototype 为原型对象

  • 原型的作用:共享方法。节约内存空间。

  • 构造函数通过原型分配的函数是所有对象所共享的。

  • JS 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。注意这个 prototype 就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有

  • 我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。

    function Star(uname, age) {
        this.uname = uname;
        this.age = age;
        /* this.sing = function() {
            console.log('我会唱歌');
        } */
    }
    Star.prototype.sing = function() {
        console.log('我会唱歌');
    };
    var ldh = new Star('刘德华', 18);
    var zxy = new Star('张学友', 19);
    ldh.sing(); // 我会唱歌
    

4.4 对象原型 __proto__

  • 对象都会有一个属性 _proto_ 指向构造函数的 prototype 原型对象
  • 方法查找规则:首先先看 对象 身上是否有 该方法,如果有就执行这个对象上的方法,如果没有,因为有 __proto__ 的存在,就去构造函数原型对象 prototype 身上去查找 该方法。
  • __proto__ 对象原型和原型对象 prototype 是等价的
  • __proto__ 只是指明一个查找方向,实际开发中,不可以使用这个属性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CmMPPkw2-1656822494853)(C:\Users\WZX\AppData\Roaming\Typora\typora-user-images\image-20220630201802262.png)]

4.5 constructor 构造函数

  • 对象原型(__proto__)和构造函数(prototype)原型对象里面都有一个属性 constructor 属性,我们称其为构造函数,因为它指回构造函数本身。

  • constructor 主要用于记录该对象引用了哪个构造函数

  • 注意:

    • 很多情况下,我们需要手动的利用 constructor 这个属性 指回原来的构造函数
    • 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
    function Star(uname, age) {
        this.uname = uname;
        this.age = age;
        /* this.sing = function() {
            console.log('我会唱歌');
        } */
    }
    /* Star.prototype.sing = function() {
        console.log('我会唱歌');
    };
    Star.prototype.movie = function() {
        console.log('我会演电影');
    }; */
    Star.prototype = {
        // 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
        constructor: Star,
        sing: function() {
        console.log('我会唱歌');
        },
        movie: function() {
        console.log('我会演电影');
    	}
    }
    
    var ldh = new Star('刘德华', 18);
    var zxy = new Star('张学友', 19);
    ldh.sing(); // 我会唱歌
    console.log(Star.prototype);
    console.log(ldh.__proto__);
    console.log(Star.prototype.constructor);
    console.log(ldh.__proto__.constructor);
    

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RXo3NuxE-1656822494859)(C:\Users\WZX\AppData\Roaming\Typora\typora-user-images\image-20220630204851614.png)]

4.7 原型链

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g8ZM1xrG-1656822494861)(C:\Users\WZX\AppData\Roaming\Typora\typora-user-images\image-20220630211651168.png)]

4.8 JS 的成员查找机制(规则)

  1. 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
  2. 如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象
  3. 如果还没有就查找原型对象的原型(Object 的原型对象
  4. 依次类推一直找到 Object 为止(null
  5. __proto__ 对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线

4.9 this 指向

  1. 在构造函数中,里面 this 指向的是 实例对象
  2. 原型对象函数里面的 this 指向的是 实例对象

4.10 扩展内置对象(原型对象的应用)

  • 可通过原型对象,对原来的内置对象进行扩展自定义方法。

    • 例子:给数组增加自定义求和的功能

      Array.prototype.sum = function() {
          var sum = 0;
          for (var i = 0; i < this.length; i++) {
              sum += this[i];
          }
          return sum;
      }
      var arr = [1,2,3];
      console.log(arr.sum()); // 6
      console.log(Array.prototype);
      
  • 注意:数组和字符串内置对象不能给原型对象覆盖操作 Array.prototype = {},只能是 Array.prototype.xxx = function() {} 的方式

5. 继承

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

5.1 call()

  • 调用这个函数,并且修改函数运行时的this指向

    fun.call(thisArg, arg1, arg2, ...)
    
    • thisArg:当前调用函数 this 的指向对象
    • arg1,arg2:传递的其他参数
    // call 方法
    function fn(x, y) {
        console.log('我想和手磨咖啡');
        console.log(this);
        console.log(x + y); // 3
    }
    var o = {
        name: 'andy'
    };
    
    // 1. call() 可以调用函数
    fn.call();
    // 2. call() 可以改变这个函数的 this 指向
    fn.call(o, 1, 2); // 此时这个函数的 this 就指向了 o
    

5.2 借用构造函数继承父类型属性

// 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            Father.call(this, uname, age);
            this.score = score;
        }
        var son = new Son('刘德华', 18, 100);
        console.log(son);

5.3 借用原型对象继承父类型方法

// 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        Father.prototype.money = function() {
            console.log(100000);

        };
        // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            Father.call(this, uname, age);
            this.score = score;
        }
        // Son.prototype = Father.prototype;  这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
        Son.prototype = new Father();
        // 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
        Son.prototype.constructor = Son;
        // 这个是子构造函数专门的方法
        Son.prototype.exam = function() {
            console.log('孩子要考试');

        }
        var son = new Son('刘德华', 18, 100);
        console.log(son);
        console.log(Father.prototype);
        console.log(Son.prototype.constructor);

6. ES5 中的新增方法

6.1 数组方法

  • 迭代(遍历)方法:forEach()、map()【和forEach相似】、filter()、some()、every()【和some相似】

  • forEach()

    • arr.forEach(function(currentValue, index, arr))
      
    • currentValue:数组当前项的值

    • index:数组当前的索引

    • arr:数组对象本身

  • filter() 方法创建一个新的数组,主要用于筛选数组

    • arr.filter(function(currentValue, index, arr))
      
      var arr = [12, 66,4, 88];
      var newArr = arr.filter(function(value, index) {
          return value > 20;
      })
      console.log(newArr); // [66, 88]
      
    • 注意它直接返回一个新数组,返回所有满足条件的元素

  • some() 方法,查找数组中是否有满足条件的元素

    • arr.some(function(currentValue, index, arr))
      
    • 注意它返回的是布尔值,找得到返回 true,找不到返回 false

    • 如果找到第一个满足条件就终止循环不继续查找了

  • forEach() 和 some() 的区别

    • forEach() 遇到 return 仍然会继续遍历数组
    • filter() 遇到 return 仍然会继续遍历数组
    • some() 遇到 return 终止循环,迭代效率更高

6.2 字符串方法

  • trim() 方法会从一个字符串的两端删除空白字符

    • str.trim()
      
    • trim() 方法不会影响字符串本身,返回的是一个新字符串

6.3 对象方法

  • Object.keys() 用于获取对象自身所有的属性

    • Object.keys(obj)
      
    • 效果类似 for…in

    • 返回一个由属性名组成的数组

  • Object.defineProperty() 定义对象中新属性或修改原有的属性

    • Object.defineProperty(obj, prop, descriptor)
      
      var obj = {
          id: 1,
          pname: '小米',
          price: 1999
      }
      Object.defineProperty(obj, 'num', {value: 1000})
      
    • obj:必须,目标对象

    • prop:必须,需要定义或修改的属性的名字

    • descriptor:必须,目标属性所拥有的特性

      • 以对象形式 {} 书写
      • value:设置属性的值,默认 undefined
      • writable:值是否可以重写。true|false 默认为 false
      • enumerable:目标属性是否可以被枚举。true|false 默认为 false(不允许遍历这个属性)
      • configurable:目标属性是否可以被删除或是否可以再次修改特性。true|false 默认为 false(不允许删除该属性同时也不允许再次修改第三个参数里面的特性【descriptor】)

7. 函数的进阶

7.1 函数的定义和调用

  1. 函数的定义方式

    1. 函数声明方式 function 关键字(命名函数)

    2. 函数表达式(匿名函数)

    3. new Function('参数1', '参数2', '函数体');(了解)

      • var f = new Function('a', 'b ''console.log(a + b)');
        f(1, 2);  // 3
        
      • Function 里面参数都必须是字符串格式

      • 这种方式执行效率低,也不方便书写,因此较少使用

      • 所有函数都是 Function 的实例对象

      • 函数也属于对象

  2. 函数的调用方式

// 函数的调用方式

        // 1. 普通函数
        function fn() {
            console.log('人生的巅峰');
        }
        // fn();   fn.call()
        // 2. 对象的方法
        var o = {
            sayHi: function() {
                console.log('人生的巅峰');
            }
        }
        o.sayHi();
        // 3. 构造函数
        function Star() {};
        new Star();
        // 4. 绑定事件函数
        // btn.onclick = function() {};   // 点击了按钮就可以调用这个函数
        // 5. 定时器函数
        // setInterval(function() {}, 1000);  这个函数是定时器自动1秒钟调用一次
        // 6. 立即执行函数
        (function() {
            console.log('人生的巅峰');
        })();
        // 立即执行函数是自动调用

7.2 this

  1. 函数内 this 的指向(一般指向我们的调用者)

    // 函数的不同调用方式决定了this 的指向不同
            // 1.** 普通函数 this 指向window **
            function fn() {
                console.log('普通函数的this' + this);
            }
            window.fn();
            // 2. 对象的方法 this指向的是对象 o
            var o = {
                sayHi: function() {
                    console.log('对象方法的this:' + this);
                }
            }
            o.sayHi();
            // 3. 构造函数 this 指向 ldh 这个实例对象 原型对象里面的this 指向的也是 ldh这个实例对象
            function Star() {};
            Star.prototype.sing = function() {
    
            }
            var ldh = new Star();
            // 4. 绑定事件函数 this 指向的是函数的调用者 btn这个按钮对象
            var btn = document.querySelector('button');
            btn.onclick = function() {
                console.log('绑定时间函数的this:' + this);
            };
            // 5. 定时器函数 this 指向的也是window
            window.setTimeout(function() {
                console.log('定时器的this:' + this);
    
            }, 1000);
            // 6. 立即执行函数 this还是指向window
            (function() {
                console.log('立即执行函数的this' + this);
            })();
    
  2. 改变函数内部 this 指向(bind()、call()、apply() 方法)

    1. call 方法

      • fun.call(thisArg, arg1, arg2, ...)
      • 既可以调用函数,又可以改变函数内 this 的指向
      • call 的主要作用可以实现继承
    2. apply 方法

      • fun.apply(thisArg, [argsArray])

      • 既可以调用函数,又可以改变函数内 this 的指向

      • 但是它的参数必须是数组(伪数组)

      • apply 的主要应用:比如我们可以利用 apply 借助于数学内置对象求最大值

        var arr = [1, 66, 88, 99];
        var max = Math.max.apply(Math, arr);
        console.log(max);
        
    3. bind 方法

      • bind.call(thisArg, arg1, arg2, ...)

      • 该方法不会调用函数,但是会改变函数内部 this 指向

      • 返回由指定的 this 值和初始化参数改造的原函数拷贝

        var o = {
            name: 'andy'
        };
        function fn(a, b) {
            console.log(this);
            console.log(a + b);
        };
        var f = fn.bind(o, 1, 2);
        f();
        
      • 主要应用:如果有的函数不需要立即调用,但是又想改变这个函数内部的 this 指向此时使用 bind

      • 例子:点击按钮后禁用,2s 后解锁按钮

                // 1. 不会调用原来的函数   可以改变原来函数内部的this 指向
                // 2. 返回的是原函数改变this之后产生的新函数
                // 3. 如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向此时用bind
                // 4. 我们有一个按钮,当我们点击了之后,就禁用这个按钮,3秒钟之后开启这个按钮
                // var btn1 = document.querySelector('button');
                // btn1.onclick = function() {
                //     this.disabled = true; // 这个this 指向的是 btn 这个按钮
                //     // var that = this;
                //     setTimeout(function() {
                //         // that.disabled = false; // 定时器函数里面的this 指向的是window
                //         this.disabled = false; // 此时定时器函数里面的this 指向的是btn
                //     }.bind(this), 3000); // 这个this 指向的是btn 这个对象
                // }
                var btns = document.querySelectorAll('button');
                for (var i = 0; i < btns.length; i++) {
                    btns[i].onclick = function() {
                        this.disabled = true;
                        setTimeout(function() {
                            this.disabled = false;
                        }.bind(this), 2000);
                    }
                }
        
    4. bind()、call()、apply() 总结

      • 相同点:都能改变函数内部 this 指向
      • 区别:
        • call、apply 会调用函数,并且改变函数内部 this 指向
        • call、apply 传递的参数不一样, apply 必须以数组形式传递
        • bind 不会调用函数,只改变 this 指向
      • 只要应用场景
        • call 经常做继承
        • apply 经常跟数组有关系,比如借助于数学对象实现数组最大值最小值
        • bind 不调用函数,但是还想改变 this 指向,比如改变定时器内部的 this 指向

8. 严格模式

8.1 什么是严格模式(ie10以上支持)

  • 严格模式对正常的 JS 语义做出了一些更改:
    1. 消除了 JS 语法的一些不合理、不严谨之处,减少了一些怪异行为
    2. 消除代码运行的一些不安全之处,保证代码运行的安全
    3. 提高编译器效率,增加运行速度
    4. 禁用了在 ECMAScript 的未来版本中可能会定义的一些语法,为未来新版本的 JS 做法铺垫。

8.2 开启严格模式

  • 严格模式可以应用到整个脚本或个别函数中。因此,严格模式分为为脚本开启严格模式为函数开启严格模式
  1. 为脚本开启严格模式

    • <script>
      	"use strict";
      </script>
      
    • 在所有语句之前放一个特定语句 “use strict”; (或 ‘use strict’; )

  2. 为函数开启严格模式

    • 把 “use strict”; (或 ‘use strict’; )声明放在函数体所有语句之前。

8.3 严格模式中的变化

  1. 变量规定

    1. 在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种用法,变量都必须先用 var 命令声明,然后再使用。
    2. 严禁删除已经声明的变量。例如:delete x; 语法是错误的。
  2. 严格模式下 this 指向问题

    1. 以前全局作用域下 this 指向 window。
    2. 严格模式下全局作用域中函数中 this 指向 undefined
    3. 以前构造函数时不加 new 也可以调用,当普通函数调用,this 指向全局对象
    4. 严格模式下,如果构造函数不加 new 调用,this 指向 undefined,如果给它赋值会报错
    5. new 实例化的构造函数指向创建的对象实例
    6. 定时器里的 this 还是指向 window
    7. 事件、对象还是指向调用者
  3. 函数变化

    1. 函数不能有重名的参数
    2. 函数必须声明在顶层,新版本的 JS 会引入“块级作用域”(ES6 中已引入)。为了于新版本接轨,不允许在非函数的代码块内声明函数。

9. 高阶函数

  • 高阶函数是对其他函数进行操作的函数,它接收函数作为参数将函数作为返回值输出

  • function fn1(callback) {
        callback && callback();
    }
    fn1(funuction() {alert('hi')})
    
    function fn2() {
        return function() {};
    }
    f2();
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值