记录

321 阅读16分钟

知识点

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
  1. promise.all 缺陷,如果即使某个promise失败的情况下依旧想要执行promise.all的then,怎么做 ###################balabala

  2. 手写promise

promise原理

  1. 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、深拷贝浅拷贝
  1. JSON.stringfy/JSON.parse可以进行深拷贝,但是undefinedfunctionsymbol 会在转换过程中被忽略
  2. Object.assign、Array.concat、Array.slice、...(解构)都是进行首层深拷贝
  3. 递归解析
  4. 循环引用如何实现深拷贝
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 执行

image.png

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的时候都做了啥
  1. new操作符会返回一个对象
  2. 这个对象可以访问挂载到this上的任意属性
  3. 这个对象可以访问原型链上的属性和方法
  4. 返回基本数据类型的数据会被忽略,返回对象会被正常使用
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

  1. 创建一个MutationObserver对象,传入回调函数callback
  2. 调用MutationObserver.observe,传入两个参数》1:要监听的元素element;2:对象的配置项
  3. dom发生变化时,回调函数执行
  4. 可以调用observer.disconnent取消监听
30、性能优化

常用的性能优化手段

image.png

31、堆栈
  1. 什么是堆栈

  2. 哪些类型的数据在堆上,哪些在栈上

  • 基本数据类型:number, boolean,string,symbol,undefined,null,bigint 在栈上;
  • 引用类型:object,function,array等在堆上。
  1. 什么情况会造成栈溢出,如何解决栈溢出
  • 递归调用会造成栈溢出;
  • 迭代替代递归可以解决栈溢出问题。
32、axios如何把异步回调转换成promise(好像是这么问的)

可以看看这个

vue

1、生命周期

生命周期剖析

image.png

2、响应式原理

响应式原理

三个步骤分析

  • 首先有响应式对象 (知道数据什么时候变化) vue2.x主要使用Object.defineProperty给数据(data、props、inject)递归添加gettersetter方法,目的是为了在获取数据或者写数据的时候能够自动执行一些逻辑

  • 收集依赖 (数据变化之后怎么通知视图更新) 数据的每个key都对应一个dep,dep包含id、subs,subs是所有依赖这个key的watcher数组,目的是为了写数据时能够派发更新

  • 派发更新 (发通知) 在写数据时,通知dep中的所有watcher,执行watcher.update

3、diff

vue的diff算法

4、 filter

filter可以链式调用,一般只用在模版渲染上

5、指令

directive:钩子函数inserted\bind\unbind\update

6、$nextTick原理

balalallaal

7、vue中,style添加scope可以使css不互相污染,vue是如何做到为标签添加scope属性的

baalalla

8、vuex

vuex原理,简单版实现

9、vue-router

vue-router揭秘

vue-router面试题

vue-router原理

image.png

image.png

image.png

哈希模式、history模式

webpack

1、webpack打包原理
  1. 读取配置文件,按命令 初始化 配置参数,创建 Compiler 对象1
  2. 调用插件的 apply 方法 挂载插件 监听,然后从入口文件开始执行编译;
  3. 按文件类型,调用相应的 Loader 对模块进行 编译,并在合适的时机点触发对应的事件,调用 Plugin 执行,最后再根据模块 依赖查找 到所依赖的模块,递归执行第三步;
  4. 将编译后的所有代码包装成一个个代码块 (Chuck), 并按依赖和配置确定 输出内容。这个步骤,仍然可以通过 Plugin 进行文件的修改;
  5. 最后,根据 Output 把文件内容一一写入到指定的文件夹中,完成整个过程;

注:1、compiler对象贯穿整个打包过程,期间会有一些钩子函数:(compilation、emit、done) compilation:创建compilation对象之后发送 emit:输出到output之前 done:完成compilation

2、chunk、module、bundle

image.png

  1. 对于一份同逻辑的代码,当我们手写下一个一个的文件,它们无论是 ESM 还是 commonJS 或是 AMD,他们都是 module
  2. 当我们写的 module 源文件传到 webpack 进行打包时,webpack 会根据文件引用关系生成 chunk 文件,webpack 会对这个 chunk 文件进行一些操作;
  3. 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'], }, ] }, };

  1. 通过 sass-loader 把 SCSS 源码转换为 CSS 代码,再把 CSS 代码交给 css-loader 去处理。
  2. css-loader 会找出 CSS 代码中的 @import 和 url() 这样的导入语句,告诉 Webpack 依赖这些资源。同时还支持 CSS Modules、压缩 CSS 等功能。处理完后再把结果交给 style-loader 去处理。
  3. style-loader 会把 CSS 代码转换成字符串后,注入到 JavaScript 代码中去,通过 JavaScript 去给 DOM 增加样式。
5、babel是什么,原理

:babel是一个 JavaScript 编译器,主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中

  1. 解析 解析步骤接收代码并输出 AST。 这个步骤分为两个阶段:词法分析(Lexical Analysis) 和 语法分析(Syntactic Analysis)。
  2. 转换 转换步骤接收 AST 并对其进行遍历,在此过程中对节点进行添加、更新及移除等操作 Babel提供了@babel/traverse(遍历)方法维护这AST树的整体状态,并且可完成对其的替换,删除或者增加节点,这个方法的参数为原始AST和自定义的转换规则,返回结果为转换后的AST。
  3. 生成 代码生成步骤把最终(经过一系列转换之后)的 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

  1. 中间件的添加是有先后顺序的,可能存在依赖关系
  2. 中间件先注册,注册完成后,等有客户端连接服务器时,中间件按照注册顺序依次执行( 洋葱模型

koa-compose实现

image.png balabala。。。

网络

1、网络安全
  1. xss攻击 (跨站脚本攻击)
  • 存储型xss

    提交恶意代码到服务器数据库,服务端收到请求时,从数据库检索到恶意代码并拼接到html返回,浏览器执行恶意代码

  • 反射型xss

    含有恶意代码的url被用户点开,服务器解析恶意代码,拼接到html中返回,浏览器执行恶意代码

  • dom型xss

    含有恶意代码的url被用户点开,浏览器收到响应后解析URL,前端js获取到恶意代码并执行

预防xss攻击: 输入过滤、html转译...

  1. csrf(跨站请求伪造)
2、缓存:强缓存,协商缓存

强缓存:当缓存数据库中已有所请求的数据时。客户端直接从缓存数据库中获取数据。当缓存数据库中没有所请求的数据时,客户端的才会从服务端获取数据

服务器返回的header中会用两个字段来标识:expires,cache-control

expires:http1.0,服务器资源到期时间

cache-control:不同的字段表示不同含义。no-cache:需要协商;no-store:不缓存;max-age=t:t秒后数据过期

image.png

协商缓存:客户端会先从缓存数据库中获取到一个缓存数据的标识,得到标识后请求服务端验证是否失效,如果没有失效服务端会返回304(客户端发送了一个get请求,且请求已经被允许,但是服务器内容没有发生变化),此时客户端直接从缓存中获取所请求的数据,如果标识失效,服务端会返回更新后的数据

Last-Modified:服务器返回数据上次修改时间

if-modified-since:浏览器发送请求时携带在缓存中获取的数据的最后修改时间

etag:服务器返回数据在服务器的唯一标识(算法生成)

if-none-match:浏览器发送请求时在缓存中获得的唯一标识

image.png

image.png

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
  1. 本地缓存有cookie;
  2. 发送的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

css

1、BFC---问的很全面,什么是bfc,怎么产生bfc,怎么解决bfc,margin重叠问题,高度塌陷问题

我觉得能理解的bfc

2、flex---问的也很全面
3、文本显示多行