知识点
javascript
1、map object的区别
map删除一项,object删除一项 map获取长度,object获取长度 :object只能用字符串、数字、symbol做key,map可以是任意类型 填入map的数据,会保持原有的顺序,而Object无法做到 map可以通过for...of迭代,object不可以
map删除:Map.prototype.delete object删除:delete Object.key
map长度:Map.prototype.size object长度:Object.keys().lenght
2、set是什么,有什么优势
:集合,每一项是唯一的,可迭代,相对于数组来说增加元素、删除元素、查找元素更快
weakmap和weakset
- 只接受对象(obj)做键名
- 键名所引用的对象(obj),是弱引用,不计入垃圾回收机制;即当没有其他对象引用该对象(obj)时,垃圾回收机制将不考虑weakmap/weakset对它的引用,直接释放该对象所占用的内存
set如何做到的去重
我没找到相关资料。。。。
3、for in 和 for of
:for...in用来遍历对象的键名,for...of一般用来遍历array的键值 for...in语句以任意顺序迭代对象的[可枚举属性],for...of 语句遍历[可迭代对象]定义要迭代的数据。
4、js基本数据类型
:string number bool undefined null symbol bigint
5、undefined 和 null 的区别
:null表示“没有对象”,即该处不应该有值,undefined表示“缺少值”,即该处应该有值,但还没有定义
6、var 和 let let和const const定义一个对象,可以修改里面的项吗 const a = {b:1}; a.b = 2;
:var存在变量提升,let必须先声明再使用 var是全局作用域,let有块级作用域概念 let该有的特性,const都有;不同的是,第一const不允许“修改”变量,第二const必须初始化
使用const声明的对象的属性是可以修改。因为Object类型是引用类型,用const声明常量保存的是对象的地址,不可变的是地址, 而修改对象的属性,并不会改变对象的地址,因此用const声明对象的属性是可以修改的. 数组也是引用类型,同理
7、暂存性死区
:let声明不会被提升到当前执行上下文的顶部,从该块级作用域开始,到初始化位置,称作“暂存死区”,所以在对于a的暂存死区中使用a会报Reference错误
8、在浏览器定义一个var 和 在node中定义一个var 有什么区别
:在 HTML 中, 全局作用域是针对 window 对象,var关键字定义的全局作用域变量属于 window 对象,而let定义的不属于。注意这是在浏览器环境下,如果是Node则无window对象。 var a = 0; console.log(window.a) // 0 let b = 1; console.log(window.b) // undefined
9、scss样式如何局部应用,原理
添加scoped属性,会给每一个标签添加data属性
12、promise
-
promise.all 缺陷,如果即使某个promise失败的情况下依旧想要执行promise.all的then,怎么做 ###################balabala
-
手写promise
- Promise 中 .then 的第二参数与 .catch 有什么区别?
catch方法之前的所有异常均能捕获到,then的第二个参数只是reject的返回
13、执行上下文、作用域链、闭包
执行上下文决定了函数可以访问哪些数据以及它们的行为
当代码执行流进入函数时,函数的上下文被推到一个上下文栈上。在函数执行完之后,上下文栈会弹出该函数上下文,将控制权返还给之前的执行上下文
在定义函数时,就会为它创建作用域链,预装载全局变量对象,并保存在内部的[[Scope]]中。在调用这个函数时,会创建相应的执行上下文,然后通过复制函数的[[Scope]]来创建其作用域链。接着会创建函数的活动对象(用作变量对象)并将其推入作用域链的前端
当函数执行完毕之后,其局部活动对象会被销毁,内存中就只剩下全局作用域,但是闭包不会,因为作用域链中还存在着闭包数据的引用,只有在闭包函数销毁之后,其数据才会销毁
14、词法作用域(静态作用域)
- JavaScript 采用的是词法作用域,函数的作用域在函数定义的时候就决定了。
- 而与词法作用域相对的是动态作用域,函数的作用域是在函数调用的时候才决定的。
15、this,call,apply,bind
实现mycall
Function.prototype.mycall = function(context,...args){
let ctx = context || window;
let func = Symbol();
ctx[func] = this;
args = args ? args :[]
const res = args.length > 0 ? ctx[func](...args):ctx[func]()
delete ctx[func]
return res
}
实现myapply
Function.prototype.myapply = function(context,args = []){
let ctx = context || window;
let func = Symbol();
ctx[func] = this;
const res = args.length > 0 ? ctx[func](...args):ctx[func]()
delete ctx[func]
return res
}
实现mybind
Function.prototype.mybind = function(context,...args){
let fn = this;
args = args?args:[]
return function newfn(...newargs){
if(this instanceof newfn){
return fn(...args,...newargs)
}
return fn.apply(context,[...args,...newargs])
}
}
连续调用bind会多次改变this的值吗
答:不会。原理balabalabala
16、说一说对象原型
原型:为其他对象提供共享属性的对象
每个对象都有一个隐性引用__proto__,它被称为对象的prototype原型
在一个对象创建时,它被隐性的挂载了另一个对象的引用,放置在__proto__属性中,这就是我们说的原型
因为prototype对象也是一个对象,所以它内部也存在自己的隐式引用__proto__,有自己的prototype对象,这就出现了原型链
17、深拷贝浅拷贝
- JSON.stringfy/JSON.parse可以进行深拷贝,但是
undefined、function、symbol会在转换过程中被忽略 - Object.assign、Array.concat、Array.slice、...(解构)都是进行首层深拷贝
- 递归解析
- 循环引用如何实现深拷贝
function deepClone(source){
if(source instanceof RegExp) return new RegExp(source);
if(source instanceof Date) return new Date(source);
if(!source || !(source instanceof Object)) return source
let result = source instanceof Array ? [] :{}
for(let key in source){
if(source.hasOwnProperty(key)){
if(source[key] && source[key] instanceof Object){
result[key] = source[key] instanceof Array ?[]:{}
result[key] = deepClone(source[key])
}else{
result[key] = source[key]
}
}
}
return result
}
18、instanceof 和 typeof
instanceof 返回值 boolean,obj instanceof Object用来检测constructor.prototype是否存在于参数obj的原型链上
typeof 返回值 字符串, typeof null== 'object'可以区分出undefined、String、Boolean、Number、BigInt、Array、Function、Symbol,其余都是Object
19、事件循环
浏览器环境和node环境 https://zhuanlan.zhihu.com/p/54882306
- Node 端,microtask 在事件循环的各个阶段之间执行
- 浏览器端,microtask 在事件循环的 macrotask 执行完之后执行; process.nextTick是独立于 Event Loop 之外的,它有一个自己的队列,当每个阶段完成后,如果存在 nextTick 队列,就会清空队列中的所有回调函数,并且优先于其他 microtask 执行
20、Web Worker
实现了javascript的‘多线程’技术
let worker = new Worker('./work.js')
//监听消息
worker.addEventListener('message', function (e) {
console.log('MAIN: ', 'RECEIVE', e.data);
});
// 或者可以使用 onMessage 来监听事件:
// worker.onmessage = function () {
// console.log('MAIN: ', 'RECEIVE', e.data);
//};
//监听错误消息
worker.addEventListener('error', function (e) {
console.log('MAIN: ', 'ERROR', e);
console.log('MAIN: ', 'ERROR', 'filename:' + e.filename + '---message:' + e.message + '---lineno:' + e.lineno);
});
// 或者可以使用 onerror 来监听错误:
// worker.onerror = function () {
// console.log('MAIN: ', 'ERROR', e.data);
//};
// 触发事件,传递信息给 Worker
worker.postMessage('Hello Worker, I am main.js');
//终止worker
worker.terminate()
21、Proxy和Object.defineProperty
Object.defineProperty无法探测到对象根属性的添加和删除,以及直接给数组下标进行赋值
22、箭头函数
- 没有this
- 没有arguments
- 不能做构造函数,不能new
- 没有prototype
- 书写简单
23、script标签的defer和sync是什么含义
defer和sync都是异步加载;
- defer:异步加载,加载完成后等到所有元素解析完成,
DOMContentLoaded事件触发之前执行 - sync:异步加载,加载完成立即执行
24、函数式编程思想:实现compose
balabalabala
25、ajax可以取消请求吗
var xhr = new XMLHttpRequest();
xhr.open("GET","https://api.github.com/");
xhr.send();
xhr.onreadystatechange=function(){
if(xhr.readyState==4&&xhr.status==200){
console.log(xhr.response);
}else{
console.log(xhr.status);
}
}
xhr.abort();
26、&& 和 || 有优先级吗
没有
测试代码:
var i = 1;
var t = true || ((function(){i = 2;return true;})() && (function(){return false;})())
console.log(t,i)
var i = 1;
var t = ((function(){i = 2;return true;})() && (function(){return false;})()) || true ;
console.log(t,i);
27、new的时候都做了啥
- new操作符会返回一个对象
- 这个对象可以访问挂载到this上的任意属性
- 这个对象可以访问原型链上的属性和方法
- 返回基本数据类型的数据会被忽略,返回对象会被正常使用
function myNew(Content,...args){
let obj = {}
obj.__proto__ = Content.prototype
let result = Content.apply(obj,...args);
return result instanceof Object ? result : obj
}
function test(){
this.name = "qiao"
}
let qiao = myNew(test)
console.log(qiao)
28、 prototype 和 __proto__
prototype是要传递给儿子的,
__proto__是爸爸传递下来
function Foo(){}
console.log(Foo.prototype)
console.log(Foo.prototype.constructor)
console.log(Foo.__proto__)
console.log(Foo.prototype.__proto__)
29、如何监听dom发生变化
使用MutationObserver
- 创建一个
MutationObserver对象,传入回调函数callback; - 调用
MutationObserver.observe,传入两个参数》1:要监听的元素element;2:对象的配置项 - dom发生变化时,回调函数执行
- 可以调用
observer.disconnent取消监听
30、性能优化
常用的性能优化手段
31、堆栈
-
什么是堆栈
-
哪些类型的数据在堆上,哪些在栈上
- 基本数据类型:number, boolean,string,symbol,undefined,null,bigint 在栈上;
- 引用类型:object,function,array等在堆上。
- 什么情况会造成栈溢出,如何解决栈溢出
- 递归调用会造成栈溢出;
- 迭代替代递归可以解决栈溢出问题。
32、axios如何把异步回调转换成promise(好像是这么问的)
vue
1、生命周期
2、响应式原理
三个步骤分析
-
首先有响应式对象 (知道数据什么时候变化) vue2.x主要使用
Object.defineProperty给数据(data、props、inject)递归添加getter、setter方法,目的是为了在获取数据或者写数据的时候能够自动执行一些逻辑 -
收集依赖 (数据变化之后怎么通知视图更新) 数据的每个key都对应一个dep,dep包含id、subs,subs是所有依赖这个key的watcher数组,目的是为了写数据时能够派发更新
-
派发更新 (发通知) 在写数据时,通知dep中的所有watcher,执行
watcher.update
3、diff
4、 filter
filter可以链式调用,一般只用在模版渲染上
5、指令
directive:钩子函数inserted\bind\unbind\update
6、$nextTick原理
balalallaal
7、vue中,style添加scope可以使css不互相污染,vue是如何做到为标签添加scope属性的
baalalla
8、vuex
9、vue-router
vue-router原理
哈希模式、history模式
webpack
1、webpack打包原理
- 读取配置文件,按命令 初始化 配置参数,创建 Compiler 对象1;
- 调用插件的 apply 方法 挂载插件 监听,然后从入口文件开始执行编译;
- 按文件类型,调用相应的 Loader 对模块进行 编译,并在合适的时机点触发对应的事件,调用 Plugin 执行,最后再根据模块 依赖查找 到所依赖的模块,递归执行第三步;
- 将编译后的所有代码包装成一个个代码块 (Chuck), 并按依赖和配置确定 输出内容。这个步骤,仍然可以通过 Plugin 进行文件的修改;
- 最后,根据 Output 把文件内容一一写入到指定的文件夹中,完成整个过程;
注:1、compiler对象贯穿整个打包过程,期间会有一些钩子函数:(compilation、emit、done) compilation:创建compilation对象之后发送 emit:输出到output之前 done:完成compilation
2、chunk、module、bundle
- 对于一份同逻辑的代码,当我们手写下一个一个的文件,它们无论是 ESM 还是 commonJS 或是 AMD,他们都是 module
- 当我们写的 module 源文件传到 webpack 进行打包时,webpack 会根据文件引用关系生成 chunk 文件,webpack 会对这个 chunk 文件进行一些操作;
- webpack 处理好 chunk 文件后,最后会输出 bundle 文件,这个 bundle 文件包含了经过加载和编译的最终源文件,所以它可以直接在浏览器中运行
3、plugin和loader的区别
loader是一个转换器,将A文件进行编译形成B文件,这里操作的是文件,比如将 A.scss 转换为 A.css,是单纯的文件转换过程。
plugin 是插件扩展器,针对webpack打包的过程,它不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些事件钩子,执行任务。plugin 比loader 强大,通过plugin 可以访问 compliler和compilation过程,通过钩子拦截 webpack 的执行。
常用的plugin;
SplitChunkPlugin:分包插件
HtmlWebpackPlugin
ExtractTextWebpackPlugin :把css提取到单独的文件
HotModuleReplacementPlguin:热更新
CopyWebpackPlugin:文件拷贝到构建目录
常用的loader
scss-loader:
css-loader:解析import和url()
style-loader:将css样式内联到style中
4、webpack配置如何解析scss
module.exports = { module: { rules: [ { // 增加对 SCSS 文件的支持 test: /.scss$/, // SCSS 文件的处理顺序为先 sass-loader 再 css-loader 再 style-loader use: ['style-loader', 'css-loader', 'sass-loader'], }, ] }, };
- 通过 sass-loader 把 SCSS 源码转换为 CSS 代码,再把 CSS 代码交给 css-loader 去处理。
- css-loader 会找出 CSS 代码中的 @import 和 url() 这样的导入语句,告诉 Webpack 依赖这些资源。同时还支持 CSS Modules、压缩 CSS 等功能。处理完后再把结果交给 style-loader 去处理。
- style-loader 会把 CSS 代码转换成字符串后,注入到 JavaScript 代码中去,通过 JavaScript 去给 DOM 增加样式。
5、babel是什么,原理
:babel是一个 JavaScript 编译器,主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中
- 解析 解析步骤接收代码并输出 AST。 这个步骤分为两个阶段:词法分析(Lexical Analysis) 和 语法分析(Syntactic Analysis)。
- 转换 转换步骤接收 AST 并对其进行遍历,在此过程中对节点进行添加、更新及移除等操作 Babel提供了@babel/traverse(遍历)方法维护这AST树的整体状态,并且可完成对其的替换,删除或者增加节点,这个方法的参数为原始AST和自定义的转换规则,返回结果为转换后的AST。
- 生成 代码生成步骤把最终(经过一系列转换之后)的 AST 转换成字符串形式的代码,同时还会创建源码映射(source maps)。 深度优先遍历整个 AST,然后构建可以表示转换后代码的字符串 Babel使用 @babel/generator 将修改后的 AST 转换成代码,生成过程可以对是否压缩以及是否删除注释等进行配置,并且支持 sourceMap
6、HRM热更新原理
balabala---没有找到好理解的文章
Node
1、在a.js中require(b.js),在b.js中require(a.js),会不会造成循环引用
2、 node的模块机制是commonjs,说说AMD\CMD\commonjs的区别
3、commonjs和Es Module
-
Commonjs 总结
Commonjs的特性如下:- CommonJS 模块由 JS 运行时实现。
- CommonJs 是单个值导出,本质上导出的就是 exports 属性。
- CommonJS 是可以动态加载的,对每一个加载都存在缓存,可以有效的解决循环引用问题。
- CommonJS 模块同步加载并执行模块文件。
-
es module 总结
Es module的特性如下:- ES6 Module 静态的,不能放在块级作用域内,代码发生在编译时。
- ES6 Module 的值是动态绑定的,可以通过导出方法修改,可以直接访问修改结果。
- ES6 Module 可以导出多个属性和方法,可以单个导入导出,混合导入导出。
- ES6 模块提前加载并执行模块文件,
- ES6 Module 导入模块在严格模式下。
- ES6 Module 的特性可以很容易实现 Tree Shaking 和 Code Splitting。
4、node 热更新
nodemon监测到文件变化后自动重启服务器,不需要手动重启,但是也会重启服务器
不重启服务器进行热更新原理:检测到文件的变化后,将缓存区中已加载的模块移除,直到下一次请求该模块的时候,重新加载对应模块
5、 Events
node中EventEmitter的emit是同步的,官方文档有说明The EventListener calls all listeners synchronously in the order in which they were registered.
const EventEmitter = require('events');
let emitter = new EventEmitter();
emitter.on('myEvent', () => {
console.log('hi 1');
});
emitter.on('myEvent', () => {
console.log('hi 2');
});
emitter.emit('myEvent');
6、对koa和express知道多少
koa: 认识koa
- 中间件的添加是有先后顺序的,可能存在依赖关系
- 中间件先注册,注册完成后,等有客户端连接服务器时,中间件按照注册顺序依次执行( 洋葱模型 )
koa-compose实现
balabala。。。
网络
1、网络安全
- xss攻击 (跨站脚本攻击)
-
存储型xss
提交恶意代码到服务器数据库,服务端收到请求时,从数据库检索到恶意代码并拼接到html返回,浏览器执行恶意代码
-
反射型xss
含有恶意代码的url被用户点开,服务器解析恶意代码,拼接到html中返回,浏览器执行恶意代码
-
dom型xss
含有恶意代码的url被用户点开,浏览器收到响应后解析URL,前端js获取到恶意代码并执行
预防xss攻击: 输入过滤、html转译...
- csrf(跨站请求伪造)
2、缓存:强缓存,协商缓存
强缓存:当缓存数据库中已有所请求的数据时。客户端直接从缓存数据库中获取数据。当缓存数据库中没有所请求的数据时,客户端的才会从服务端获取数据
服务器返回的header中会用两个字段来标识:expires,cache-control
expires:http1.0,服务器资源到期时间
cache-control:不同的字段表示不同含义。no-cache:需要协商;no-store:不缓存;max-age=t:t秒后数据过期
协商缓存:客户端会先从缓存数据库中获取到一个缓存数据的标识,得到标识后请求服务端验证是否失效,如果没有失效服务端会返回304(客户端发送了一个get请求,且请求已经被允许,但是服务器内容没有发生变化),此时客户端直接从缓存中获取所请求的数据,如果标识失效,服务端会返回更新后的数据
Last-Modified:服务器返回数据上次修改时间
if-modified-since:浏览器发送请求时携带在缓存中获取的数据的最后修改时间
etag:服务器返回数据在服务器的唯一标识(算法生成)
if-none-match:浏览器发送请求时在缓存中获得的唯一标识
3、 https加密算法
服务器将公钥传递给CA机构进行加密,CA机构添加上域名、时长等信息来制作证书,并用CA机构私钥加密后,返回给服务器,服务器将这段加密数据配置在服务器上
当浏览器向服务器发送请求时,服务器会首先将这段加密数据返回给浏览器,浏览器使用CA机构的公钥对其进行解密,获取到公钥;浏览器只需要从操作系统中遍历内置的CA机构的公钥,只要有一个可以解密,这个公钥就是可用的,即浏览器安全的获取到了公钥
然后浏览器和服务器就可以进行数据传输
4、浏览器打开一个页面有多少个进程
5、cookie和session
- cookie保存在客户端;session保存在服务器;
http请求是无状态的,服务器无法辨别发送请求的客户端的身份; 为了解决该问题,在建立链接时,服务器为每个客户端创建一个session,提供一个sessionId; 客户端发送请求时,在请求头上设置cookie,在cookie中携带上sessionId,发送到服务器,服务器通过sessionId判断用户身份
cookie是请求返回时,服务器返回给客户端的信息,客户端收到会保存起来cookie;当客户端再次发送请求时,会携带上cookie发送到服务器
6、浏览器发送请求自动携带上cookie
- 本地缓存有cookie;
- 发送的URL能够匹配上cookie的domain和path属性 满足以上两点,浏览器发送请求才会自动携带上cookie
7、跨域
jsonp 和 数据埋点的img 跨域阻塞发生在哪个阶段
8、进程、线程
题
1、给定一个非空数组,求出现最高的数据,以数组形式返回
eg. [1,2,2,3] 返回:[2] [1,‘2’,‘2’,1,3,null,null] 返回:[1,‘2’,null]
tip:使用map
2、给定一个整数无序数组和变量sum,如果存在数组中任意两项和等于 sum 的值,则返回true。否则,返回false。
eg. 数组[3,5,1,4] sum = 9, 返回true 因为4 + 5 = 9
tip: 使用set