this

普通函数的this指向需要根据函数直接调用的位置来判断

  1. 通过new调用时this会绑定到新创建的对象上
  2. 通过call,apply,bind调用时,在严格模式下绑定到指定的第一个参数,非严格模式下第一个参数如果是null或undefined指向全局对象window,其余值指向被new Object()包装的对象
  3. 对象上的函数调用时绑定到那个对象上
  4. 普通函数直接调用,在严格模式下绑定到undefined上,非严格模式绑定到全局对象window
  5. 在dom事件中一般指向绑定事件的dom元素,但有些情况也会绑定到全局对象中例如IE6-8中

箭头函数的this指向是继承外层代码块的this

箭头函数与普通函数的区别

  1. 箭头函数不能作为构造函数,因为它没有constructor构造器
  2. 不可以使用argument对象,可以用es6的剩余参数代替
  3. 不可以使用yield指令,因为箭头函数不能做generator函数
  4. 箭头函数没有自己的this,不能使用call,apply,bind这些方法去改变this指向

    new操作符做了什么

  5. 创建一个空对象

  6. 将空对象的proto属性指向构造函数的prototype属性
  7. 将构造函数中的this指向新创建的新对象,并执行函数逻辑
  8. 如果构造函数有显式指定返回对象或函数则返回指定的对象或函数否则返回new操作符创建的对象

    apply、call、bind的区别

  9. 三者都可以改变this指向

  10. 三者第一个参数都是this要指向的对象,如果没有这个参数或是参数值为undfined或null,则默认指向全局对象window
  11. 三者都可以传参,但是apply是数组,而calll, bind是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入
  12. bind是返回绑定this之后的函数,便于稍后调用,apply,call则是立即执行,bind会返回一个新的函数,,如果这个返回的新函数作为构造函数创建新的实例对象那么创建实例的过程中this不是指向原先bind的对象而是指向new创建的实例

继承

通过extends关键字继承后的类new之后的实例对象包含父类自身的属性方法也包含构造函数的属性方法,它们都属于这个实例对象自身的属性方法

Object类型的实例函数

hasOwnProperty

该函数的作用是判断对象自身是否拥有指定名称的实例属性,此函数不会检查实例对象原型上的属性

in

该关键字的作用是判断对象自身是否拥有指定名称的实例属性,此关键字会检查实例对象原型上的属性

区别:hasOwnProperty只看对象本身有没有指定的key,而in关键字则是看自身或是原型链上有没有指定的key

propertyIsEnumerable

该函数的作用是判断指定名称的属性是否为实例属性并且是否可枚举,如果是原型链上的属性或者不可枚举都将返回false

Objec类型的静态属性

Object.create

该函数的主要作用是创建并返回一个指定原型和指定属性的对象

  1. Object.create(prototype, {
  2. propertyName: {
  3. value: '', //设置此属性的值
  4. writable: true, // 设置此属性是否可写入,默认是false只读
  5. enumerable:true, // 设置此属性是否可枚举,默认为false不可枚举
  6. configurable: true, // 设置此属性是否可配置(是否能删除|是否能修改)默认是false无法配置
  7. }
  8. })
  9. // prototype 是一个对象可以传null,如果是null则对象的原型为undefined

Object.freeze

对对象进行冻结,即不能增删改对象中的属性,以及不能修改对象已有属性的可枚举性,可配置性,可写性。对于不会进行修改的大对象可以使用Object.freeze()优化性能

  1. 只是浅冻结,要深层冻结需要递归
  2. vue中使用Object.freeze()可以让vue不去添加响应,有利于性能优化

    instanceof

    instanceof运算符用于通过查找原型链来检测某个变量是否为某个数据类型的实例

    1. function A () {...}
    2. const a = new A()
    3. a intanceof A // true
    4. // instaceof 是通过查找原型链来作为是否属于的判断标志
    5. // 也可以直接用构造函数判断
    6. a.constructor === A
    7. // 通过constructor属性可以拿到实例的构造函数

    数组去重的7个方法

  3. 新增一个空数组再去遍历数组判一下新数组中不存在这个元素就可以push进去

  4. 通过对象去重,遍历数组以值为key都插入对象,最后把Object.keys转回数组
  5. 先排序数组然后新增一个空数组塞进去数组的第一个然后循环排序好的数组如果新数组的第i项不等于排序数组的第i项就push,就能得到不重复数组
  6. 通过reduce去重
  7. 借助ES6的Set数据结构
  8. 借助ES6的Map数据结构

    Map的使用

    ```javascript const map = new Map() or const map = new Map([[key, value], [‘aa’, 111]]) // 新增修改 map.set(key, value)’ // 判读有无 map.has(key) // 获取 map.get(key) // 删除 map.delete(key) //清除所有 map.clear() // 循环 map.forEach /*
  • map.forEach((item, key)=> {…}) // item为值,key为键 */ // 返回字符串表式 map.toString() // [object Map] // 返回对象的原始值 也就是map map.valueOf() // 元素个数 map.size ```

    Map与普通对象的差别

    Map的key区分String和Number,而普通对象的key不区分
    Map可以用任何数据类型做key,而普通对象如果用引用类型做key会直接调用toString方法得到对象的字符串表示在存储值
    Map的key-value表现为二维数组,而普通对象则是对象形式

Set的使用

  1. const set = new Set()
  2. // 新增
  3. set.add(value)
  4. //删除
  5. set.delect(value)
  6. // 是否包含
  7. set.has(value)
  8. // 清除
  9. set.clear()
  10. // 遍历
  11. set.keys()
  12. set.values()
  13. set.entries()
  14. set.forEach()
  15. // 长度
  16. set.size

set是一个不重复的集合

RegExp

静态属性$n为只读属性,且只有匹配成功才会改写,如果前一条正则匹配到了,后一条正则没有匹配到,那么$n中的内容还是前一条的, 只要$1匹配成功重写后面的也就会跟着清空重写
n最大值为9,因为正则最多只能有九个匹配项

Date

date对象计算时间差时可以直接比较,他会通过隐性转换规则调用valueOf方法转成时间戳去比较
处理date字符串时最好是用正则替换成“/”形式,出于兼容性考虑,因为在ios中“-”拼接会转不成时间

  1. date.setDate(date.getDate() + 3) // 3天后
  2. 通过setDate可以将date实例转到nnn年后

Function

Function构造函数的缺点

  1. Function构造函数每次执行,都会解析函数主体,并创建一个新的函数对象,效率较低
  2. 使用Function构造函数创建的函数并不遵循典型的作用域,它将一直作为顶级函数执行,所以在函数A内部调用Function构造函数时,其中的函数体并不能访问到函数A中的局部变量,而是只能访问到全局变量
    ```javascript function foo() {…} // 函数声明 var foo = function() {…} // 函数表达式

``` 以上两者的区别:
函数声明是存在函数提升的,也就是可以先使用后定义函数, 而对于函数表达式是不存在的函数提升的,也就是在声明前调用就会抛出错误

形参与实参

如果实参是引用类型那可以在函数内去操作这个引用类型的属性给它增删查改,但不能去改地址值,如果进行整个全新赋值那是不会影响的外面的传入的实参的

arguments

在argument中有一个特别的属性callee,它会指向当前正在执行的函数,这个属性在匿名递归函数中可以用的上。不过通过arguments.callee() 去调用函数的话函数的this指向就变成了argument了,因为是通过arguments去调用的

构造函数

在编写构造函数的时候我们会把属性构造函数中,方法放构造函数的原型上,这也做的目的是为了避免重复的创建实例上的function对象,如果把方法放构造函数上就让每次实例化都去创建那些方法。

变量/函数提升

用var申明的变量与具名function都存在变量/函数提升。变量提升的优先级高于函数提升也就是函数在var变量声明的后面

闭包

闭包的用途

  1. 对于那种处理很耗时的函数对象可以利用闭包不会释放外部引用内存的方式将处理结果存到闭包的引用的外层的变量中缓存起来当执行相同条件的函数调用时就可以直接从原先的缓存中取。
  2. 私有化变量属性,可以利用闭包的特点进行函数封装,将私有变量定义在函数内并返回私有变量的get, set方法限制函数外部的上下文环境对私有遍历的操作。
  3. 防抖节流函数

    闭包的缺点

  4. 消耗内存,由于闭包引用外部的外包变量在函数执行完后仍然存在引用无法被浏览器的垃圾回收机制回收就会一直占据内存空间。

  5. 过渡使用可能会照成内存泄露