读《前端开发核心知识进阶》短记(一)

目录

  • 前言
  • 第一部分:JavaScript基础强化
    • 01. 一网打尽this
      this规则 this优先级 call、bind、apply三者的区别 new操作符的作用 定义实现一个bind函数
    • 02. 闭包
      作用域 执行代码的两个阶段 执行上下文 闭包 内存管理 内存泄露
    • 03. 实现API
      offset方法和getBoundClientRect方法暂时不写 数组reduce方法实现 reduce方法实现runPromise reduce方法实现pipe 实现compose 实现apply函数
    • 04. JavaScript高频考点及基础题库
      typeof instanceof Object.prototype.toString.call 判断类型万能方法 数据类型转换 函数参数传递 因undefined访问对象属性时报错

前言

侯策写的这本书,针对中高级前端开发的查漏补缺和面试很有帮助,所以看过一遍之后将需要记录的知识点总结一遍。

第一部分:JavaScript基础强化

01. 一网打尽this

this规则

  1. 简单调用函数,严格模式下为undefined,非严格模式下为window
  2. New方法构造函数时,指向新创建的对象上,如果返回的是一个对象,则指向返回的对象
  3. 使用call/apply/bind时,指向第一个参数指定的对象
  4. 通过上下文调用函数时,指向对应上下文对象上
  5. 箭头函数时,对应箭头函数外的作用域
  6. 如果上下文调用中有嵌套关系,this会指向最后调用它的对象

this优先级

显式绑定:call、apply、bind、new
隐式绑定:根据调用关系确定this指向的情况
优先级:
显式绑定 > 隐式绑定
new > call、apply、bind
箭头函数的this不可变
tips:const声明的变量不会挂载到window全局对象上

call、bind、apply三者的区别

call和apply直接进行相关函数的调用,bind不会调用而是返回一个新函数,call和bind都需要参数单个传,apply需要将参数转为数组。

new操作符的作用

  1. 定义一个对象
  2. 对象的__proto__属性指向new构造函数的原型对选哪个
  3. 对象上定义一些属性和方法
  4. 返回这个对象

定义实现一个bind函数

Function.prototype.bind = Function.prototype.bind || function(context) {
    const _this = this;
    // arguments为类数组,用call调用数组的slice
    const args = Array.prototype.slice.call(arguments, 1);
    return function () {
        const finalArgs = args.concat(Array.prototype.slice.call(arguments));
        return _this.apply(context, finalArgs);
    }
}

02. 闭包

作用域

ES5:全局作用域,函数作用域
ES6:原有基础上添加块级作用域
变量作用域查找是根据作用域链,依次跳到上层,终点在全局。

暂时性死区(TDZ):

  • 在声明(let,const)之前
  • 函数参数复制默认值之前(默认值为undefined)

执行代码的两个阶段

执行代码分为代码预编译阶段代码执行阶段

  • 代码预编译阶段:确定作用域,进行变量声明
  • 代码执行阶段:创建执行上下文,执行上下文形成作用域链

执行上下文

执行上下文指的是当前代码的执行环境/作用域
执行上下文包括:变量对象、作用域链、this

闭包

函数嵌套函数时,内层引用外层变量,且内层函数全局可访问,形成闭包。(Closure 闭包变量)

闭包基本原理:
外界可以通过返回的函数获取原函数内部的变量值。

内存管理

  • 生命周期:分配内存,读写内存,释放内存
  • 栈空间由操作系统自动分配释放(基本数据类型),堆空间由开发者分配释放(引用类型)

tips:Javascript依赖浏览器的垃圾回收机制

内存泄露

空间不再使用却没有释放的现象,会导致程序变慢或崩溃。
解决该问题就需要将该空间使用完手动置为null

03. 实现API

offset方法和getBoundClientRect方法暂时不写

数组reduce方法实现

Array.prototype._reduce = function(fn, initval) {
    const arr = this
    let base = typeof initval === 'undefined' ? arr[0] : initval
    let initIndex = typeof initval === 'undefined' ? 1 : 0
    arr.slice(initIndex).forEach((val, index) => {
        base = fn(base, val, initIndex + index, arr)
    })
    return base
}

reduce方法实现runPromise

const runPromisesInSeries = (promiseArr, value) => promiseArr.reduce((result, promiseFnc) => promiseFnc.then(result), Promise.then(value))

reduce方法实现pipe

const pipe = (...fns) => input => fns.reduce((result, val) => val(result), input)

实现compose

const compose = (...fns) => {
    const len = fns.length;
    return function(...args) {
        let index = 0;
        // 先运算出第一个结果,this指向调用的函数
        let result = len ? fns.reverse()[index].apply(this, args) : args[0];
        // 循环运算出其他的结果
        while(++index < len) {
            result = fns[index].call(this,result);
        }
        return result;
    }
}

实现apply函数

Function.prototype.apply = Function.prototype.apply || function(context, ...args) {
    // 判断参数
    if (typeof args === 'undefined' || args === null) args = [];
    if (typeof context === 'undefined' || context === null) context = window;
    // 在context上定义一个属性applyKey接收要执行的函数
    context.applyKey = this;
    // 利用上下文调用方式让this指向context
    const result = context.applyKey(...args);
    // 将多余的属性删除
    delete context.applyKey;
    // 返回运行结果
    return result;
}

04. JavaScript高频考点及基础题库

typeof

只判断基础类型(除null以外),引用类型只有‘function’,‘object’
特殊:

typeof null => 'object'
typeof NaN => 'number'
typeof [] => 'object'

instanceof

a instanceof b,是判断a是否可以在b的原型链中找到,所以基本数据类型直接返回false
原理:

function instanceFunc(L,R) {
    // 如果是原始类型直接返回false
    if(typeof L !=== 'object') return false;
    while(true) {
        // 如果原型链查找完成直接返回false
        if(L.__proto__ === null) return false;
        // 如果在原型链中找到了,返回true
        if(L.__proto__ === R.prototype) return true;
        // 在原型链继续查找
        L = L.__proto__;
    }
}

Object.prototype.toString.call 判断类型万能方法

Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call('An').slice(8, -1) => 'String'

数据类型转换

JavaScript是弱类型的语言,或可说动态语言
"+":

  • string + any => string
  • number + undefined => NaN
  • number + number、boolean、null => number
  • NaN + number、boolean、NaN、undefined、null => NaN
  • Infinity + Infinity、number、boolean、null => Infinity
  • Infinity + (-Infinity)、number、boolean、null => -Infinity
  • Infinity + (-Infinity) => NaN
  • 引用类型:先调用valueOf或toString由规范所决定,先转成基本数据类型再字符串拼接

(tips: 可以通过对对象的valueOf和toString方法重写,改变 console.log(1+foo) 的结果,隐式转换更倾向于调用valueOf

优先级:string > undefined(NaN) > number > boolean

函数参数传递

  • 函数为基础数据类型时,复制参数值,修改不会改变原值
  • 参数为引用类型时:
    • 修改某值,原值跟着修改(引用同一地址)
    • 修改引用地址,修改值原值不会修改

因undefined访问对象属性时报错

  1. && 短路运算符
  2. || 设置保底默认值
  3. try-catch方法
  4. lodash get方法
  5. ?. 可选链操作符

你可能感兴趣的:(读《前端开发核心知识进阶》短记(一))