@panhonhang
2020-02-17T16:18:56.000000Z
字数 7013
阅读 401
面试
数组:博文
为什么用promise:解决回调地狱,改成链式调用。
错误处理:接口未报错,请求成功。用状态码判断。
如何promise的then方法:1、每一次成功之后再返回一个promise。(1、Promises/A+标准:原Promise对象的状态将跟新对象保持一致。)
async await实现原理:async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。
function objectFactory() {
var obj = new Object(),
//取出第一个参数,就是我们要传入的构造函数
Constructor = [...arguments].shift();
obj.__proto__ = Constructor.prototype;
Constructor.apply(obj, arguments);
return obj;
}
实现数组扁平化:
//方法一
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
var result = [];
for (var i = 0, len = arr.length; i < len; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]));
}
else {
result.push(arr[i])
}
}
return result;
}
console.log(flatten(arr))
//方法二
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
return arr.toString().split(',').map(function(item){
return +item
})
}
console.log(flatten(arr))
// 方法三
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
console.log(flatten(arr))
直接遍历对象会报错!!!遍历对象必须给对象添加 Symbol.iterator 属性
其实一种数据结构只要部署了 Iterator 接口,我们就称这种数据结构是“可遍历的”(iterable)。由此,我们也可以发现 for of 遍历的其实是对象的 Symbol.iterator 属性。
所以 for...of 循环可以使用的范围包括:
数组
Set
Map
类数组对象,如 arguments 对象、DOM NodeList 对象
Generator 对象
字符串
for...in 循环只遍历可枚举属性,是为遍历对象属性而构建的,不建议与数组一起使用,数组可以用Array.prototype.forEach()和for ... of,那么for ... in的到底有什么用呢?
它最常用的地方应该是用于调试,可以更方便的去检查对象属性
1、对 this 的关联。函数内置 this 的值,取决于箭头函数在哪儿定义,而非箭头函数执行的上下文环境。
2 、new 不可用。箭头函数不能使用 new 关键字来实例化对象,不然会报错。
3、this 不可变。函数内置 this 不可变,在函数体内整个执行环境中为常量。
4、没有arguments对象。更不能通过arguments对象访问传入参数。只能使用显式命名或其他ES6新特性来完成。
箭头函数永远不能用作构造函数,自然的不能使用new关键字调用它们,因此,对于箭头函数不存在prototype属性。、
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。
数组、对象、字符串、数值和布尔值、函数参数
每一次链式调用then操作返回的都是新的promise
分开调用返回的then相同
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
javascript直接实现;
SVG(可伸缩矢量图形);
CSS3 transition;(补间动画)
CSS3 animation;(帧动画)
Canvas动画;
requestAnimationFrame;
优化动画提高性能?
首先考虑css动画然后考虑js。其次可以用window.requestAnimationFrame()
function Pubsub(){
//存放事件和对应的处理方法
this.handles = {};
}
Pubsub.prototype={
//传入事件类型type和事件处理handle
on: function (type, handle) {
if(!this.handles[type]){
this.handles[type] = [];
}
this.handles[type].push(handle);
},
emit: function () {
//通过传入参数获取事件类型
var type = Array.prototype.shift.call(arguments);
if(!this.handles[type]){
return false;
}
for (var i = 0; i < this.handles[type].length; i++) {
var handle = this.handles[type][i];
//执行事件
handle.apply(this, arguments);
}
},
off: function (type, handle) {
handles = this.handles[type];
if(handles){
if(!handle){
handles.length = 0;//清空数组
}else{
for (var i = 0; i < handles.length; i++) {
var _handle = handles[i];
if(_handle === handle){
handles.splice(i,1);
}
}
}
}
}
}
框架相关:
生命周期:
生命周期
主要答出批处理
1.this.setState(newState) =>
2.newState存入pending队列 =>
3.调用enqueueUpdate =>
4.是否处于批量更新模式 => 是的话将组件保存到dirtyComponents
5.不是的话遍历dirtyComponents,调用updateComponent,更新pending state or props
enqueueUpdate的源码如下:
function enqueueUpdate(component){
//injected注入的
ensureInjected();
//如果不处于批量更新模式
if(!batchingStrategy.isBatchingUpdates){
batchingStrategy.batchedUpdates(enqueueUpdate, component);
return;
}
//如果处于批量更新模式
dirtyComponents.push(component);
}
如果isBatchingUpdates为true,则对所有队列中的更新执行batchedUpdates方法,否则只把当前组件(即调用了setState的组件)放入dirtyComponents数组中,例子中4次setState调用的表现之所以不同,这里的逻辑判断起了关键作用。
实现:
洋葱圈模型
compose函数
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
const last = funcs[funcs.length - 1]
const rest = funcs.slice(0, -1)
return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
}
compose(f, g, h)(...args)效果等同于 f(g(h(...args)))
redux 中间件通过改写 store.dispatch 方法实现了action ->reducer的拦截,从上面的描述中可以更加清晰地理解 redux 中间件的洋葱圈模型
发布订阅模式
组件如何订阅store状态的呢?
使用 subscribe 订阅,subscribe 这个函数是用来去订阅 store 的变化,比如你每次对 store 进行 dispatch(action) 都会触发 subscribe注册的函数调用,这个在实际情况不是必须要的,看自己的应用场景,比如你想监控 store 的全局变化时 可以用 subscript 订阅一下,然后作一些反应。
function throttle(fn, interval = 300) {
let canRun = true;
return function () {
if (!canRun) return;
canRun = false;
setTimeout(() => {
fn.apply(this, arguments);
canRun = true;
}, interval);
};
}
function debounce(fn, interval = 300) {
let timeout = null;
return function () {
clearTimeout(timeout);
timeout = setTimeout(() => {
fn.apply(this, arguments);
}, interval);
};
}
1.Object.assign() 不是完全的深拷贝
2.JSON.parse(JSON.stringify())
3.for in 循环
1、直接使用eval()函数
eval("("+JSON+")")
2、循环递归
const re = /(\d{4})-(\d{2})-(\d{2})/;
const match= re.exec('2019-01-01');
console.log(match[0]); // → 2019-01-01
console.log(match[1]); // → 2019
console.log(match[2]); // → 01
console.log(match[3]); // → 01
typeof与instanceof区别:
typeof判断基本类型比较好。
instanceof 运算符是用来测试一个对象是否在其原型链原型构造函数的属性。其语法是object instanceof constructor
instanceof 操作符用来比较两个操作数的构造函数。只有在比较自定义的对象时才有意义。 如果用来比较内置类型,将会和 typeof 操作符 一样用处不大。
HTTP与HTTPS区别
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
ajax请求:Ajax请求过程
使用了PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH方法
人为设置了非规定内的其他首部字段,参考上面简单请求的安全字段集合,还要特别注意Content-Type的类型
XMLHttpRequestUpload 对象注册了任何事件监听器
请求中使用了ReadableStream对象
http1.0 exprires last-modified 连接无法复用
http1.1 etag cache-control 支持长连接(connection) 支持文件断点续传
http2.0 多路复用 首部压缩 服务器推送 管线操作 二进制传输,传输速度更快了
更多参考:勤奋蜂复习:http缓存
缓存字段优先级:
Cache-Control > Expires > ETag > Last-Modified
Expires:
Cache-Control
private: 客户端可以缓存
public: 客户端和代理服务器都可缓存
max-age=xxx: 缓存的内容将在 xxx 秒后失效
no-cache: 需要使用对比缓存来验证缓存数据(后面介绍)
no-store: 所有内容都不会缓存,强制缓存,对比缓存都不会触发
If-None-Match:
Etag:
我们可以看到两类缓存规则的不同,强制缓存如果生效,不需要再和服务器发生交互,而对比缓存不管是否生效,都需要与服务端发生交互。两类缓存规则可以同时存在,强制缓存优先级高于对比缓存,也就是说,当执行强制缓存的规则时,如果缓存生效,直接使用缓存,不再执行对比缓存规则。
对比缓存:
对比缓存,顾名思义,需要进行比较判断是否可以使用缓存,需要与服务器进行交互。
浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。
再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。
2XX
200 OK 表明请求已经成功. 默认情况下状态码为200的响应可以被缓存。
201 Created 是一个代表成功的应答状态码,表示请求已经被成功处理,并且创建了新的资源。通常是POST 请求的返回值
202 Accepted 表示服务器端已经收到请求消息,但是尚未进行处理。
204 No Content 成功状态响应码,表示该请求已经成功了,但是客户端客户不需要离开当前页面。默认情况下 204 响应是可缓存的。一个 ETag 标头包含在此类响应中。
3XX
301 永久重定向 说明请求的资源已经被移动到了由 Location 头部指定的url上,是固定的不会再改变。搜索引擎会根据该响应修正。
难点:前期调查、接口与需求文档、后期测试、项目当中。