JavaScript

1. 数据类型

  • 按存储类型分类:(基本类型)number, string, boolean, undefined, null;(引用类型, 对象)Object, Array, Function;

  • typeof:number, string, boolean, undefined, null(object), function, array(object)

  • instanceof:A.__proto__ === B.prototype; 注意都是true:Object instanceof Function; Function instanceof Object; Function instanceof Function

  • Object.prototype.toString.call 相对有效

  • 比较稳的方法:

    let class2type = {}
    'Array Date RegExp Object Error'.split(' ').forEach(e => class2type[ '[object ' + e + ']' ] = e.toLowerCase()) 
    
    function type(obj) {
        if (obj == null) return String(obj)
        return typeof obj === 'object' ? class2type[ Object.prototype.toString.call(obj) ] || 'object' : typeof obj
    }
    

2. new运算符的执行过程

例如:var a = new A();

  • 创建一个新对象:var obj = new Object(); obj.__proto__ = A.prototype;

  • 将构造函数的作用域赋给新对象(因此this就指向了这个对象):A.bind(obj)

  • 执行构造函数中的代码(为这个新对象添加属性):A()

  • 返回新对象(如果构造函数有自己 retrun 时,则返回该值)

  • polyfill:

    function New (f) {
        var n = { '__proto__': f.prototype }; //步骤1
        return function () {
            f.apply(n, arguments); //步骤2和3
            return n; //步骤4
        };
    }
    

3. this 关键字

常见用法

  • 对象的方法调用,this指向对象
  • 函数调用中的 this,严格模式是 window,非严格模式是 undefined
  • 构造函数中的this,指向构造函数的实例化对象

三种显式改变this绑定

  • call:fn.call(target, 1, 2)

  • apply:fn.apply(target, [1, 2]) 配合 arguments 很好用,内部会转换成 call,所以效率上call更快

  • bind:fn.bind(target)(1,2) 一般不立即执行的时候使用,bind 里面的 this 指向,不会被重写 a.bind(b).call(c)最终的 this 是 b

  • 应用:

    • 获取数组中的最大值和最小值:Math.max.apply(Math, numbers);
    • 判断类型:Object.prototype.toString.call(target)
    • 数组里面的使用需要注意:arr[0]() 等效 arr.0.call(arr)

this的绑定原则

  • 严格模式下默认绑定的是undefined, 非严格模式 this 指向了 window 和 global
  • setTimeOut 这样在函数中以函数作为参数的,非严格模式下this指向全局对象
  • 优先级:new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
  • fn(...args) 等效fn.call(window [ES5-strict: undefined], ...args)

箭头函数

箭头函数表达式的语法比函数表达式更短,并且不绑定自己的this,arguments,super或 new.target。这些函数表达式最适合用于非方法函数(non-method functions),并且它们不能用作构造函数。

  • 没有 arguments,使用 rest参数的形式访问

  • 没有构造函数,所以不能使用 new

  • 没有原型

  • 箭头函数中this直接指向的是调用函数的上一层运行时

  • 一个特殊的对比

    function test () {
      setTimeout(function () {
        console.log(this);
      }, 0)
    }
    test.call({a: 'this is obj'}) // Window
    
    function test () {
      (() => {
        console.log(this);
      })()
    }
    test.call({a: 'this is thisArg'}) // Object {a: 'this is thisArg'}
    

例子

var length = 10;
function fn() {
    console.log(this.length);
}
var obj = {
  length: 5,
  method: function(fn) {
    fn();
    arguments[0]();
  }
};
obj.method(fn, 1);//输出是什么?

4. 数组方法(es6方法斜体)

通过Object.getOwnPropertyNames(Array.prototype)得到浏览器支持方法

  • 9个会改变自身值的方法,使用需谨慎:pop, push, reverse, shift, sort, splice, unshift, copyWithin, fill

    • sort:各大浏览器的算法不是统一的

    • splice:三个参数(起始下标、删除个数、添加元素),返回删除的项目数组集合

  • 8个不会改变自身的方法:concat, join, slice, toString, toLocateString, indexOf, lastIndexOf, includes,flat, flatMap

  • concat, slice:一般的数组拷贝可以使用它们,但是他们的集合里面如果有引用类型的对象,是不会复制的,只会继续引用

    • includes:相比 indexOf 多一个查找 NaN 的能力 [NaN, 1].includes(NaN); [NaN, 1].indexOf(NaN)>-1; // true; false
  • flat:多维数组拍平一维数组

  • 12个遍历的方法: forEach, every, some, filter, map, reduce, reduceRight, find, findIndex, entries, keys, values

    • forEach:将为数组中每一项执行一次函数,那些已删除,新增或者从未赋值的项将被跳过(但不包括值为 undefined 的项)
  • some:接收的方法返回true,后面的立即停止

    • reduce:接收的参数第一个为累加器方法,这个方法有四个参数(accumulator,currentValue, currentIndex, array自身);第二个为初始值 initialValue,如果有初始值,作为第一个accumulator值,否则accumulator 的值为数组第一个,currentIndex 从1开始;在没有初始值的空数组上调用 reduce 将报错
  • map 相比 forEach多了个返回值,如果遍历对象不是引用类型就不会影响元素组的值

    • entries, keys, values:涉及到迭代器
  • 伪数组转换

    • var arr = Array.prototype.slice.call(aLi)
    • Array.from(arguments)

5. 深拷贝和浅拷贝

比较前还需要弄清除赋值,赋值

  • 基本数据类型:赋值,赋值之后两个变量互不影响
  • 引用数据类型:赋,两个变量具有相同的引用,指向同一个对象,相互之间有影响

简单来说可以理解为浅拷贝只解决了第一层的问题,拷贝第一层的基本类型值,以及第一层的引用类型地址

  • 浅拷贝的方法:

    • obj2 = Object.assign({}, obj);
    • obj2 = {...obj};
    • arr2 = arr.slice(0);
    • arr2 = arr.concat([])
  • 深拷贝的方法:

    • JSON.parse(JSON.stringify(obj))
      • 缺陷:
        • undefinedsymbol 和函数这三种情况,会直接忽略。
        • 循环引用情况下,会报错。
        • 正则直接转对象了
    • lodash.cloneDeep()

6. 字符串方法

所有字符串方法都不会改变自身

  • 操作:slice, substr, substring, trim, toLowerCase, toUpperCase, toLocaleLowerCase, toLocaleUppercase, replace, split, toString, valueOf;

  • 查找比较:charAt, charCodeAt, indexOf, lastIndexOf, search, match, localeCompare, includes

  • html相关:anchor, link, big, blink, bold

  • 支持正则高阶用法:match, search, replace, split

7. 正则

  • 元字符

    • 基本 ---> . \ |
    • 字符组 ---> [] [^] [-]
    • 数量 ---> {m,n} {m,} {m} + * ? |
    • 位置 ---> ^ $ \b \B (?=p) (?!p)
    • 特殊 ---> \d \D \s \S \w \W
    • 标志 ---> g i m
  • 简写

    • \d (\D) digit ---> [0-9]
    • \w (\W) word ---> [0-9a-zA-Z_]
    • \s \S space ---> [\t\v\n\r\f]
    • . ---> [^\n\r\u2028\u2029]
    • ? ---> {0,1}
    • + ---> {1, }
    • * ---> {0,}
  • 惰性:数量相关的概念

    • 默认贪婪'aaaa'.match(/\w{2,5}/) // 'aaaa'
    • 加上?转为惰性 'aaaa'.match(/\w{2,5}?/) // 'aa'

8. 模块化

  • CommonJS:require/module.exports 浏览器没有那两个关键字不支持,只能在 node 中使用

    • 从它分裂出 AMDAsynchronous Module Definition规范(requireJS),可以作用在浏览器上

    • 基于它,CMD规范(seaJS),和 AMD 主要差别:AMD是一个依赖提前加载的概念,而CMD是同步执行,遇到require之后再执行当前的一个模块。两个都是单例模式

  • ECMAScript6:import/export

  • 相关:JS MODULE 大战

上次更新: 6/5/2020, 3:22:23 AM