整理一下最近前端的充电笔记,惭愧以前一直没有去很好的理解原型和闭包

JS高级基础

函数的理解和使用

  • 函数也是对象

    • instanceof Object===true

    • 函数有属性: prototype

    • 函数有方法: call()/apply()

    • 可以添加新的属性/方法

  • 函数的3种不同角色

    • 一般函数 : 直接调用

    • 构造函数 : 通过new调用

    • 对象 : 通过.调用内部的属性/方法

  • 函数中的this

    • 显式指定谁: obj.xxx()

    • 通过call/apply指定谁调用: xxx.call(obj)

    • 不指定谁调用: xxx() : window

    • 回调函数: 看背后是通过谁来调用的: window/其它

  • 匿名函数自调用:

    (function(w, obj){
      //实现代码
    })(window, obj)
    • 专业术语为: IIFE (Immediately Invoked Function Expression) 立即调用函数表达式

  • 回调函数的理解

    • 什么函数才是回调函数?

      • 你定义的

      • 你没有调用

      • 但它最终执行了(在一定条件下或某个时刻)

    • 常用的回调函数

      • dom事件回调函数

      • 定时器回调函数

      • ajax请求回调函数

      • 生命周期回调函数

原型与原型链

  • 所有函数都有一个特别的属性:

    • prototype : 显式原型属性

  • 所有实例对象都有一个特别的属性:

    • __proto__ : 隐式原型属性

  • 显式原型与隐式原型的关系

    • 函数的prototype: 定义函数时被自动赋值, 值默认为{}, 即用为原型对象

    • 实例对象的__proto__: 在创建实例对象时被自动添加, 并赋值为构造函数的prototype值

    • 原型对象即为当前实例对象的父对象

  • 原型链

    • 所有的实例对象都有__proto__属性, 它指向的就是原型对象

    • 这样通过__proto__属性就形成了一个链的结构---->原型链

    • 当查找对象内部的属性/方法时, js引擎自动沿着这个原型链查找

    • 当给对象属性赋值时不会使用原型链, 而只是在当前对象中进行操作

闭包

  • 理解:

    • 当嵌套的内部函数引用了外部函数的变量时就产生了闭包

    • 闭包本质是内部函数中的一个对象, 这个对象中包含引用的变量属性

  • 作用:

    • 延长局部变量的生命周期

    • 让函数外部能操作内部的局部变量

  • 随便写一个闭包程序

    function fn1() {
      var a = 2;
      function fn2() {
        a++;
        console.log(a);
      }
      return fn2;
    }
    var f = fn1();
    f();
    f();
  • 闭包应用:

    • 模块化: 封装一些数据以及操作数据的函数, 向外暴露一些行为

    • 循环遍历加监听

    • JS框架(如:jQuery)大量使用了闭包

  • 缺点:

    • 变量占用内存的时间可能会过长

    • 可能导致内存泄露

    • 解决:

      • 及时释放 : f = null; //让内部函数对象成为垃圾对象

js线程

  • js是单线程执行的(回调函数也是在主线程)

  • 只能是主线程更新界面

定时器问题:

  • 定时器并不真正完全定时

  • 如果在主线程执行了一个长时间的操作, 可能导致延时才处理

理解ES

  1. 全称: ECMAScript
  2. js语言的规范
  3. 我们用的js是它的实现
  4. js的组成
  • ECMAScript(js基础)
  • 扩展-->浏览器端
    • BOM
    • DOM
  • 扩展-->服务器端
    • Node.js

ES5

  1. 严格模式

  • 运行模式: 正常(混杂)模式与严格模式
  • 应用上严格式: 'strict mode';
  • 作用:
    • 使得Javascript在更严格的条件下运行
    • 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为
    • 消除代码运行的一些不安全之处,保证代码运行的安全
    • 需要记住的几个变化
      • 声明定义变量必须用var
      • 禁止自定义的函数中的this关键字指向全局对象
      • 创建eval作用域, 更安全
  1. JSON对象

  • 作用: 用于在json对象/数组与js对象/数组相互转换
  • JSON.stringify(obj/arr) js对象(数组)转换为json对象(数组)
  • JSON.parse(json) json对象(数组)转换为js对象(数组)
  1. Object扩展

  • Object.create(prototype[, descriptors]) : 创建一个新的对象
    • 以指定对象为原型创建新的对象
    • 指定新的属性, 并对属性进行描述
      • value : 指定值
      • writable : 标识当前属性值是否是可修改的, 默认为true
      • get方法 : 用来得到当前属性值的回调函数
      • set方法 : 用来监视当前属性值变化的回调函数
  • Object.defineProperties(object, descriptors) : 为指定对象定义扩展多个属性
  1. Array扩展

  • Array.prototype.indexOf(value) : 得到值在数组中的第一个下标
  • Array.prototype.lastIndexOf(value) : 得到值在数组中的最后一个下标
  • Array.prototype.forEach(function(item, index){}) : 遍历数组
  • Array.prototype.map(function(item, index){}) : 遍历数组返回一个新的数组
  • Array.prototype.filter(function(item, index){}) : 遍历过滤出一个子数组
  1. Function扩展

  • Function.prototype.bind(obj)
    • 将函数内的this绑定为obj, 并将函数返回
  • 区别bind()与call()和apply()?
    • fn.bind(obj) : 指定函数中的this, 并返回函数
    • fn.call(obj) : 指定函数中的this,并调用函数
  1. Date扩展
  • Date.now() : 得到当前时间值
  • ...

对象的扩展一般通过原型

ES6

  1. 2个新的关键字

  • let/const
  • 块作用域
  • 没有变量提升
  • 不能重复定义
  • const定义值不可变
  1. 变量的解构赋值

  • 将包含多个数据的对象(数组)一次赋值给多个变量
  • 数据源: 对象/数组
  • 目标: {a, b}/[a, b]
  1. 各种数据类型的扩展

  • 字符串

    • 模板字符串
      • 作用: 简化字符串的拼接
      • 模板字符串必须用``
      • 变化的部分使用${xxx}定义
    • contains(str) : 判断是否包含指定的字符串
    • startsWith(str) : 判断是否以指定字符串开头
    • endsWith(str) : 判断是否以指定字符串结尾
    • repeat(count) : 重复指定次数
  • 对象

    • 简化的对象写法

      let name = 'Tom';
      let age = 12;
      let person = {
          name,
          age,
          setName (name) {
              this.name = name;
          }
      };
      
    • Object.assign(target, source1, source2..) : 将源对象的属性复制到目标对象上

    • Object.is(v1, v2) : 判断2个数据是否完全相等

    • __proto__属性 : 隐式原型属性

  • 数组

    • Array.from(v) : 将伪数组对象或可遍历对象转换为真数组
    • Array.of(v1, v2, v3) : 将一系列值转换成数组
    • find(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素
    • findIndex(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素下标
  • 函数

    • 箭头函数
      • 用来定义匿名函数
      • 基本语法:
        • 没有参数: () => console.log('xxxx')
        • 一个参数: i => i+2
        • 大于一个参数: (i,j) => i+j
        • 函数体不用大括号: 默认返回结果
        • 函数体如果有多个语句, 需要用{}包围
      • 使用场景: 多用来定义回调函数
    • 形参的默认值
      • 定义形参时指定其默认的值
    • rest(可变)参数
      • 通过形参左侧的...来表达, 取代arguments的使用
    • 扩展运算符(...)
      • 可以分解出数组或对象中的数据
  1. set/Map容器结构

  • 容器: 能保存多个数据的对象, 同时必须具备操作内部数据的方法
  • 任意对象都可以作为容器使用, 但有的对象不太适合作为容器使用(如函数)
  • Set的特点: 保存多个value, value是不重复 ====>数组元素去重
  • Map的特点: 保存多个key--value, key是不重复, value是可以重复的
  • API
    • Set()/Set(arr) //arr是一维数组
    • add(value)
    • delete(value)
    • clear();
    • has(value)
    • size
    •  
    • Map()/Map(arr) //arr是二维数组
    • set(key, value)
    • delete(key)
    • clear()
    • has(key)
    • size
  1. for--of循环

  • 可以遍历任何容器
  • 数组
  • 对象
  • 伪/类对象
  • 字符串
  • 可迭代的对象
  1. Promise

  • 解决回调地狱(回调函数的层层嵌套, 编码是不断向右扩展, 阅读性很差)

  • 能以同步编码的方式实现异步调用

  • 在es6之前原生的js中是没这种实现的, 一些第三方框架(jQuery)实现了promise

  • ES6中定义实现API:

    // 1. 创建promise对象
    var promise = new Promise(function(resolve, reject){
      // 做异步的操作
      if(成功) { // 调用成功的回调
        resolve(result);
      } else { // 调用失败的回调
        reject(errorMsg);
      }
    })
    // 2. 调用promise对象的then()
    promise.then(function(
      result => console.log(result),
      errorMsg => alert(errorMsg)
    ))
    
  1. 模块化 模块化规范(CommonJS和ES6规范最常用)

  • CommonJS

    • Node.js : 服务器端

    • Browserify : 浏览器端 也称为js的打包工具

    • 基本语法:

      • 定义暴露模块 : exports

        exports.xxx = value
        module.exports = value
        

        引入模块 : require

        var module = require('模块名/模块相对路径')
        
    • 引入模块发生在什么时候?

      • Node : 运行时, 动态同步引入
      • Browserify : 在运行前对模块进行编译/转译/打包的处理(已经将依赖的模块包含进来了), ​ 运行的是打包生成的js, 运行时不存在需要再从远程引入依赖模块 ES6
  • ES6内置了模块化的实现

  • 基本语法

    • 定义暴露模块 : export

      • 暴露一个对象:

        export default 对象
        
      • 暴露多个:

        export var xxx = value1
        export let yyy = value2
        
        var xxx = value1
        let yyy = value2
        export {xxx, yyy}
        
    • 引入使用模块 : import

      • default模块:

        import xxx  from '模块路径/模块名'
        
      • 其它模块

        import {xxx, yyy} from '模块路径/模块名'
        import * as module1 from '模块路径/模块名'
        
  • 问题: 所有浏览器还不能直接识别ES6模块化的语法

  • 解决:

    • 使用Babel将ES6--->ES5(使用了CommonJS) ----浏览器还不能直接支行
    • 使用Browserify--->打包处理----浏览器可以运行

ES7

  • 指数运算符: **
  • Array.prototype.includes(value) : 判断数组中是否包含指定value
  • 区别方法的2种称谓
    • 静态(工具)方法
      • Fun.xxx = function(){}
    • 实例方法
      • 所有实例对象 : Fun.prototype.xxx = function(){} //xxx针对Fun的所有实例对象
      • 某个实例对象 : fun.xxx = function(){} //xxx只是针对fun对象
01-11 01:10