目录
- 前言
- 第一部分: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访问对象属性时报错
- 01. 一网打尽this
前言
侯策写的这本书,针对中高级前端开发的查漏补缺和面试很有帮助,所以看过一遍之后将需要记录的知识点总结一遍。
第一部分:JavaScript基础强化
01. 一网打尽this
this规则
- 简单调用函数,严格模式下为undefined,非严格模式下为window
- New方法构造函数时,指向新创建的对象上,如果返回的是一个对象,则指向返回的对象
- 使用call/apply/bind时,指向第一个参数指定的对象
- 通过上下文调用函数时,指向对应上下文对象上
- 箭头函数时,对应箭头函数外的作用域
- 如果上下文调用中有嵌套关系,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操作符的作用
- 定义一个对象
- 对象的
__proto__
属性指向new构造函数的原型对选哪个 - 对象上定义一些属性和方法
- 返回这个对象
定义实现一个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访问对象属性时报错
- && 短路运算符
- || 设置保底默认值
- try-catch方法
- lodash get方法
- ?. 可选链操作符