Javascript
-
数据类型
基本数据类型:string、number、boolean、symbol、undefined、null;
引用类型:Object、Array、Function、Map等;
-
判断数据类型方法
typeof:能够快速区分基本数据类型,但是引用类型判断都返回object(eg: console.log(typeof function(){}); // function);
instanceof:能够快速区分引用类型,适合判断自定义类实例对象,但是基本数据类型不能判断(eg:console.log(2 instanceof Number); // false);
Object.prototype.toString.call:精准判断所有数据类型(eg:console.log(toString.call(null)); //[object Null]);
-
原型、原型链
原型:实例对象上有
__proto__
隐式原型、构造函数上有prototype
原型对象;__proto__
指向构造函数的prototype
。原型链:原型与原型层层相连接的过程就是原型链。
原型链
-
var、let、const
var:声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象,可重复定义;
let:声明的变量,其作用域为该语句所在的代码块内,不存在变量提升;
const:声明的变量不允许修改;
-
闭包
假如一个函数能访问外部的变量,那么这个函数它就是一个闭包,而不是一定要返回一个函数;
-
闭包使用场景
-
在全局作用域中读取内部函数的变量;
-
防止函数内部的变量执行完成后被销毁,使其一直保存在内存中;
-
封装私有变量;
-
-
继承
原型链继承:将函数prototype指向新的对象,基于原型链,既是父类的实例,也是子类的实例;缺点是无法实现多继承,所有实例都会共享父类实例的属性;
构造继承:将函数call绑定this,可以实现多继承(call多个),解决了所有实例共享父类实例属性的问题;缺点是只能继承父类实例的属性和方法,不能继承原型上的属性和方法;
组合继承:将上面两种组合使用,可以继承实例属性/方法,也可以继承原型属性/方法;缺点是调用了两次父类构造函数,生成了两份实例;
-
浅拷贝、深拷贝
浅拷贝:只拷贝对象里面的数据,不拷贝对象里面的子对象;浅拷贝可以通过assign和三点扩展运算符方式实现
深拷贝:克隆出一个新的对象,数据相同,但引用地址不同;深拷贝可以通过loadash.cloneDeep实现,或者递归拷贝,或者转json字符串再转json(会忽略undefined、symbol,不能序列化函数和解决循环引用对象);
-
call、apply、bind
三个函数的作用都是将函数绑定到上下文中,用来改变函数中this的指向,借用已实现的方法,减少重复代码,节省内存。
call:改变函数的this上下文后马上执行该函数,接收参数若干个参数列表;
Function.prototype.myCall = function(context, ...args) {
context = context || window
let fn = Symbol()
context[fn] = this
let result = context[fn](...args)
delete context[fn]
return result
}
apply:改变函数的this上下文后马上执行该函数,接收参数是数组;
Function.prototype.myApply = function(context) {
context = context || window
let fn = Symbol()
context[fn] = this
let result
if (arguments[1]) {
result = context[fn](...arguments[1])
} else {
result = context[fn]()
}
delete context[fn]
return result
}
bind:返回改变了上下文后的函数,不执行该函数,接收参数若干个参数列表;
Function.prototype.myBind = function (context) {
var _this = this
var args = [...arguments].slice(1)
// 返回一个函数
return function F() {
// 因为返回了一个函数,我们可以 new F(),所以需要判断
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}
- ==和===区别
==:两边值类型不同的时候,要先进行类型转换,再比较
-
如果类型不同,进行类型转换
-
判断比较的是否是 null 或者是 undefined, 如果是, 返回 true .
-
判断两者类型是否为 string 和 number, 如果是, 将字符串转换成 number
-
判断其中一方是否为 boolean, 如果是, 将 boolean 转为 number 再进行判断
-
判断其中一方是否为 object 且另一方为 string、number 或者 symbol , 如果是, 将 object 转为原始类型再进行判断
===:不做类型转换,类型不同的一定不等
- 防抖和节流
防抖:防止函数多次调用,将多次执行变为最后一次执行;
节流:防止函数多次调用,将多次执行变为每隔一段时间执行;
- 宏任务和微任务
宏任务(Task):同步代码、setTimeout 回调、setInteval 回调、IO、UI 交互事件、postMessage、MessageChannel;
微任务(MicroTask):Promise 状态改变以后的回调函数(then 函数执行,如果此时状态没变,回调只会被缓存,只有当状态改变,缓存的回调函数才会被丢到任务队列)、Mutation observer 回调函数、queueMicrotask 回调函数(新增的 API);
宏任务会被丢到下一次事件循环,并且宏任务队列每次只会执行一个任务;微任务会被丢到本次事件循环,并且微任务队列每次都会执行任务直到队列为空;假如每个微任务都会产生一个微任务,那么宏任务永远都不会被执行了;
- EventLoop
-
执行�同步代码
-
执行完所有同步代码后且执行栈为空,判断是否有微任务需要执行
-
执行所有微任务且微任务队列为空
-
是否有必要渲染页面
-
执行一个宏任务
- localStorage、sessionStorage、cookie、indexDB
localStorage:一直存在,除非手动清理,存储大小5M;
sessionStorage:tab标签页关闭就自动清理,存储大小5M;
cookie:由服务器生成、可设置过期时间,每次携带在请求header中,存储大小4K;
indexDB:一直存在,除非手动清理,存储大小没有限制;
- 模块化
AMD:依赖前置,提前执行 (require.js),语法是define,require
CMD:依赖就近,延迟执行 (sea.js),语法是 define,seajs.use([],cb)
CommonJS:CommonJS语法 module.exports=fn或者exports.a=1; 通过require('./a1')来引入;CommonJs模块首次执行会被缓存,再次加载只返回缓存结果,require返回的值是输出值的拷贝(对于引用类型是浅拷贝)
ES6 Module:es6 module 语法是 export {...}, import ...from..., export输出的是值得引用
NodeJS、webpack都是基于CommonJS该规范来实现的
- CommonJS和ES6 Module区别
-
Commonjs是同步导入,因用于服务端,文件都在本地,同步导入即使卡住主线程影响也不大,后者是异步导入,因为用于浏览器端,需下载文件,如果采用同步导入对渲染会有很大影响。
-
CommonJS 在导出时都是值的拷贝,就算导出的值变了,导入的值也不会变。如果想更新,必须重新导入一回。
-
ES Module 导入导出的值指向同一个内存地址。所以,导入值也会随着导出值变化。
-
ES Module 会编译成 require/exports来执行。
网友评论