JS Proxy

Proxy

Proxy可以取消代理

var obj = {
    a: 1
}
  , handles = {
    get(target, key, context) {
        console.log("accessing:", key);
        return target[key];
    },
}
  , {proxy: pobj, revoke: prevoke} = Proxy.revocable(obj, handles)

console.log(pobj.a);
// accessing: a
// 1

prevoke();

pobj.a
// Uncaught TypeError: Cannot perform 'get' on a proxy that has been revoked

JS Symbol

Symbol

Symbol.species

用于控制生成新实例时,类的内置方法使用哪个构造器

Symbol.iterator

用于生成对象的迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var a = {
1: "张三",
2: "12"
}
a[Symbol.iterator] = function() {
index = 0;
return {
next: ()=>{
index++;
return {
value: this[index],
done: !this[index]
}
}

}
}

for (var i of a) {
console.log(i)
//张三
//12
}

Symbol.toPrimitive

在做类型转换时,将对象转为原生类型值

1
2
3
4
5
6
7
8
9
10
11
12
13
var arr = [1, 2, 3, 4]

console.log(arr + 10)
// 1,2,3,410

arr[Symbol.toPrimitive] = function(hint) {
if (hint === "default" || hint === "number") {
return this.reduce((acc,curr)=>acc + curr, 0)
}
}
console.log(arr + 10)
//20

Symbool

Vue解析 defineProperty与Proxy

Vue 解析 defineProperty 与 Proxy

老说 vue2,数组对象不行,不行在哪?
老说 vue3 上来,这些数组对象的问题都解决了,到底解决了什么?是真的没有问题了吗?

vue2 的 defineProperty

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
interface Props {
// true 当且仅当该属性描述符的类型可以被改变并且该属性可以从对应对象中删除。
// 默认为 false
configurable: boolean;
// true 当且仅当在枚举相应对象上的属性时该属性显现。
// 默认为 false
enumerable: false;

// true 当且仅当在枚举相应对象上的属性时该属性显现。
// 默认为 false
value: any;

// true当且仅当与该属性相关联的值可以用assignment operator改变时。
// 默认为 false
writable: boolean;

// 作为该属性的 getter 函数,如果没有 getter 则为undefined。函数返回值将被用作属性的值。
// 默认为 undefined
get?: () => any;

// 作为属性的 setter 函数,如果没有 setter 则为undefined。函数将仅接受参数赋值给该属性的新值。
// 默认为 undefined
set?:(value)=>void
}
/**
* @params obj: 修改对象
* @params key: 要修改的值
* @params Props:
*/
Object.defineProperties(obj,key, props: Props)

描述符可以有的属性

configurable enumerable value writable get set
数据描述符 可以 可以 可以 可以 不可以 不可以
存取描述符 可以 可以 不可以 不可以 可以 可以

example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var data = {
name: '张三',
}

var p = defineReactive(data)

function defineReactive(data) {
var result = data
Object.keys(data).forEach((key) => {
var value = data[key]
Object.defineProperty(result, key, {
enumerable: true,
configurable: true,
set(val) {
console.log(`set`, key, val)
value = val
},
get() {
console.log(`get`, key, value)
return value
},
})
})

return result
}

console.log(p.name)
p.name = '李四'
console.log(p.name)

console

遗留问题:

Object.defineProperty只能根据已存在的 key 来修改getset方法,所以当key不存在的时候没有办法触发getset所以需要强制刷新,使用$set

vue2 数组对象有什么问题

数组可以看成key为 0,1…的对象,也可以使用Object.defineProperty改写getset,也就是说vue2可以监控数组的数据变化,

问题 1. 当新增值的时候,数据的新的 key 没有被Object.defineProperty改写,也就没有办法触发页面刷新,因此需要用$set

问题 2. 当数组unshift插入值的时候,会修改整个数组的每个对象,所以要触发多次getset, 如下图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var data = ['张三', '李四', '王五']

var p = defineReactive(data)

function defineReactive(data) {
var result = data
Object.keys(data).forEach((key) => {
var value = data[key]
Object.defineProperty(result, key, {
enumerable: true,
configurable: true,
set(val) {
console.log(`set`, key, val)
value = val
},
get() {
console.log(`get`, key, value)
return value
},
})
})

return result
}

p.unshift('赵六')

console

解析:数组将内部对象,依次往后移动一位,最后在开始位置插入赵六数据,所以需要重复的get,set特别,是最后一个值王五,移动到 3 号位置的时候,3 号位置没有被Object.defineProperty改写,因此打印出来的数据上 3 号位置没有getset方法,也就没有触发set,console.dir(p)后也就没有触发get打印get 3 王五

vue2 如何处理

node_modules/vue/src/core/observer/array.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse',
]

/**
* Intercept mutating methods and emit events
*/
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method]
def(arrayMethods, method, function mutator(...args) {
const result = original.apply(this, args) //执行方法
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted) // 改写新插入的值
// notify change
ob.dep.notify()
return result // 返回结果
})
})

检测数组中的方法有没有被添加数据,如果添加了数据,就将添加的数据用Object.defineProperty改写。
因此也就解决了,push 后的值没有被监听的问题

遗留问题

因为要对对象的所有属性改写setget方法,所以需要递归遍历数据的元素,所以性能比较差,所以不要在vuedata上挂不需要的值。如windowjquery

vue3 的 Proxy

1
2
3
4
5
6
7
8
9
10
11

interface Handler {
get: Function
set: Function
}

/**
* @params target 代理对象
* @params handler 处理对象
*/
const p = new Proxy(target:object, handler:Handler)

example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var data = {
name: '张三',
}

var p = defineReactive(data)

function defineReactive(data) {
var result = data

p = new Proxy(result, {
set(obj, prop, value) {
console.log(`set`, prop, value)
obj[prop] = value
},
get(obj, prop) {
console.log(`get`, prop, obj[prop])

return obj[prop]
},
})

return p
}

p.name = '李四'
p.name

console

vue3 解决了 vue2 什么问题

Proxy 不需要遍历 data 的所有 key 修改 key 的 get 和 set,只需要在最上使用 Proxy,就能监听到当前对象 get 和 set。

那么当我们p.name.first="李"还能触发 set 吗

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var data = {
name: {
first: '张',
content: '三',
},
}

var p = defineReactive(data)

function defineReactive(data) {
var result = data

p = new Proxy(result, {
set(obj, prop, value) {
console.log(`set`, prop, value)
obj[prop] = value
},
get(obj, prop) {
console.log(`get`, prop, obj[prop])

return obj[prop]
},
})

return p
}

p.name.first = '李'

console

从 console 可以看出,只触发 data 的 name 的 get 方法,没有触发 set,也就是说 Proxy 只能监听代理数据的子项,不能监听代理数据的孙子项。

怎么办?

由于 Proxy 是在 Data 上监听,那么为什么不能在 get 被触发的时候,将子项也代理,从而达到监听孙子项的目的那

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var data = {
name: {
first: '张',
content: '三',
},
}

var p = defineReactive(data)

function defineReactive(data) {
var result = data

p = new Proxy(result, {
set(obj, prop, value) {
console.log(`set`, prop, value)
obj[prop] = value
},
get(obj, prop) {
console.log(`get`, prop, obj[prop])

return defineReactive(obj[prop])
},
})

return p
}

p.name.first = '李'

console

如图:监听到了 p.name.first 的 set 事件,这样就解决了数据递归遍历的噩运,提高了速度。

vue3 遗留问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var data = ['张三', '李四', '王五']

var p = defineReactive(data)

function defineReactive(data) {
var result = data

p = new Proxy(result, {
set(obj, prop, value) {
console.log(`set`, prop, value)
obj[prop] = value
},
get(obj, prop) {
console.log(`get`, prop, obj[prop])
return obj[prop]
},
})

return p
}

console.dir(p[1])

console

当 data 为数组的时候也可以监听到。但是 unshift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var data = ['张三', '李四', '王五']

var p = defineReactive(data)

function defineReactive(data) {
var result = data

p = new Proxy(result, {
set(obj, prop, value) {
console.log(`set`, prop, value)
obj[prop] = value
return true
},
get(obj, prop) {
var val = obj[prop]

if (typeof obj[prop] === 'object') {
val = defineReactive(obj[prop])
}

return val
},
})

return p
}

p.unshift('赵六')

console

由此可见:在 vue3 中使用了 Proxy 也没有解决触发多次 set 事件的问题。

vue3完整示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function reactive(data) {
if (typeof data !== 'object' || data == null) {
return data
}

const observed = new Proxy(data, {
get(target, key, receiver) {
let result = Reflect.get(target, key, receiver)

return typeof result !== 'object' ? result : reactive(result)
},

set(target, key, value, receiver) {
effective()
const ret = Refect.set(target, key, value, receiver)
return ret
},

deleteProperty(target, key) {
const ret = Refect.deleteProperty(target, key)
return ret
},
})

return observed
}

keep-alive

keep-alive

作用 缓存视图

怎么缓存 以队列到内存

缓存什么 VNode 虚拟 DOM Vue -> 数据

注意点 缓存数量限制

缓存机制 LRU 页面置换算法

时间复杂度

时间复杂度

渐进时间复杂度

若存在函数 f(n), 使得当 n 趋近于无穷大时,T(n)/f(n) 的极限值不等于零的常数,则称 f(n)是 T(n)的同数量级函数,记作 T(n) = O(f(n)), 称为 O(f(n)), O 为算法的 渐进时间复杂度,简称为时间复杂度

时间复杂度优先级

O(1) < O(logn) < O(n) < O(n^2)

React Hook

Hook 是React 16.8的新增特性, 它可以在不编写class的情况下使用state以及其他React特性

Hooks增加了函数式组件中state的使用,在之前函数式组件是无法拥有自己的状态的,只能通过 props 以及 context 来渲染自己的UI, 而在业务逻辑中, 有些场景必须要使用到 state, 那么 我们就只能将函数式组件定义为class 组件.而现在通过 Hook, 我们可以轻松的在函数式组件中保护我们的状态, 不需要更改为class组件

存在问题Class

  1. 组件间复用状态逻辑很难
  2. 复杂组件变得难以理解,高阶组件和函数组件的嵌套过深
  3. class组件存在this指向的问题
  4. 难以记忆生命周期

Hooks解决的问题

React Hooks 要解决的问题是状态共享, 这里的状态共享是指只共享状态逻辑复用,并不是数据之间的共享.我们知道在React Hooks之间,解决状态逻辑复用问题, 我们通常使用higher-order components 和 render-props.

Hook 最大的优势其实还是对于状态逻辑的复用便捷,还有代码的简洁,以及帮助函数组件增强功能

实现原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Hooks = {
memoizedState: any; // 指向当前渲染节点 Fiber
baseState: any; // 初始化 initialState, 已经每次dispatch 之后 newState
baseUpdate: Update<any> | null; // 当前需要更新的Update, 每次更新完之后,会赋值上一个 update, 方便 react 在渲染错误的边缘,数据回溯
queue: UndateQueue<any> | null; // UndateQueue 通过
next: Hook | null; // link 到下一个hooks, 通过next 串联每一个 hooks
};

type Effect = {
tag: HookEffectTag; // effectTag 标记当前hook作用在 life-cycles 的哪一个阶段
create: () => mixed; // 初始化 callback
destroy: (() => mixed) | null;
deps: Array<mixed> | null;
next: Effect;
};

Reack Hooks 全局维护了一个workInProgressHook变量, 每一次调用 Hooks API 都会首先调取 createWorkInProgressHooks函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function createWorkInProgressHook(): Hook {
if (workInProgressHook === null) {
// This is the first hook in the list
if (firstWorkInProgressHook === null) {
isReRender = false;
firstWorkInProgressHook = workInProgressHook = createHook();
} else {
// There's already a work-in-progress. Reuse it.
isReRender = true;
workInProgressHook = firstWorkInProgressHook;
}
} else {
if (workInProgressHook.next === null) {
isReRender = false;
// Append to the end of the list
workInProgressHook = workInProgressHook.next = createHook();
} else {
// There's already a work-in-progress. Reuse it.
isReRender = true;
workInProgressHook = workInProgressHook.next;
}
}
return workInProgressHook;
}

Hooks 的串联不是一个数组, 是一个链式的数据结构, 从跟节点 workInProgressHook 向下通过next 进行 串联, 这也就是 为什么 Hooks不能嵌套使用,不能在判断条件中使用,不能在循环中使用,否则回破坏链式结构

class 与 hooks的生命周期对应关系

class组件 Hooks组件
constructor useState
getDerivedStateFromProps useState里面的update函数
shouldComponentUpdate useMemo
render 函数本身
componentDidMount useLayoutEffect
componentDidUpdate useEffect
componentWillUnmount useEffect里面返回的函数
componentDidCatch
getDerivedStateFromError

setState

1
const [state, setState] = useState(initialState);

setState 函数用于更新 state。它接收一个新的 state 值并将组件的一次重新渲染加入队列。

setState(Object.assign(state,{name:'123'}) // 并不会改变 state中的name
setState({...state,{name:'123'}}) // 每次都要付给他新的值

useEffect(fn,[state…])

该 Hook 接收一个包含命令式、且可能有副作用代码的函数。useEffect 的函数会在组件渲染到屏幕之后执行。

useEffect(() => {
  const subscription = props.source.subscribe();
  return () => {
    // 清除订阅
    subscription.unsubscribe();
  };
},[state]);

当第二个参数不填,默认为所有state,当state更新都,先执行fn返回函数,后执行fn
当第二个参数为[], 取消所有组件监控,当组件更新,先执行fn返回函数,后执行fn
当第二个参数填一个state,则当前state更新则,先执行fn返回函数,后执行fn

useRef()

  1. 保存dom元素

     function TextInputWithFocusButton() {
       const inputEl = useRef(null);
       const onButtonClick = () => {
         // `current` 指向已挂载到 DOM 上的文本输入元素
         inputEl.current.focus();
       };
       return (
         <>
           <input ref={inputEl} type="text" />
           <button onClick={onButtonClick}>Focus the input</button>
         </>
       );
     }
    
  2. 保存可变值 但不会渲染到页面上

     function TextInputWithFocusButton() {
       const inputEl = useRef(null);
       const save = useRef({name:'123'});
       const onButtonClick = () => {
         // `current` 指向已挂载到 DOM 上的文本输入元素
         save.current.value = inputEl.current.value;
       };
       return (
         <>
           <input ref={inputEl} type="text" />
           <button onClick={onButtonClick}>Focus the input</button>
         </>
       );
     }
    

useContext(myContent)

 跨多层组件传值,有父组件向子组件,必须与createContext结合使用
const value = useContext(MyContext);

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

const ThemeContext = React.createContext(themes.light);

function App() {
  return (
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
  );
}

useMemo(()=>{},[默认可以不写])

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

渲染过程中执行,与useEffect不同

  1. 不给第二个参数,一定执行,每次都渲染视图
  2. 第二个参数为[], 数据怎么变都不进行视图渲染
  3. 第二个参数为[a],只有当数据a变化的时候才进行视图渲染

useCallback(()=>{}, []);

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

和useMemo一样,但是返回的是个函数,函数每次渲染都会执行,但值不变;

  1. 不给第二个参数,一定执行,每次值都变
  2. 第二个参数为[], 值不变
  3. 第二个参数为[a],只有当数据a变化的时候才进行值的变化

forwordRef((props, ref) => {})

将组件内的domRef直接暴露到组件本身上

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// 你可以直接获取 DOM button 的 ref:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

useImperativeHandle(ref, ()=> {}, [])

可以在你使用ref时自定义暴露给父组件实例的值。最好与forwardRef结合使用

function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);

第三个参数,监控state的变化

useLayoutEffect

其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。

自定义hook

  1. 必须以use开头
  2. 就是一个普通函数

useReducer(reducer,初始值,initFn) return [state, dispatch]

前端面试题

React、redux, vue、vue-router实现原理、 vuex、vue双向绑定的实现原理。

redux-React状态管理 参考文档

使用情况

    某个组件的状态,需要共享
    某个状态需要在任何地方都可以拿到
    一个组件需要改变全局状态
    一个组件需要改变另一个组件的状态

设计思路

    Web 应用是一个状态机,视图与状态是一一对应的。
    所有的状态,保存在一个对象里面。

基本概念

    1. Store 保存数据的地方,可以看成一个容器,整个应用中只有一个store
    2. State 对象包含的数据,如果想得到某个时点的数据,就要对store生成快照,这个时点的数据集合就叫state
    3. Action State的变化会导致View的变化,用户接触不到State,只能接触View,State的变化必须是View导致的,Action就是View发出,用来改变State的
    4. Reducer Store收到Action之后,必须给出一个新的State,这样View才会发生变化,这种State的计算过程就叫做Reducer
    5. Store.dispatch()发出Action , store.subscribe() 监听变化

vue-router

    “haschange”,“pushstate”,“replacestate”

HTTPS 三次握手、浏览器垃圾回收机制、service worker主要作用。

自动垃圾回收机制(GC:Garbage Collecation)

标记清除

    function test(){
    var a = 10 ;             //被标记 ,进入环境 
    var b = 20 ;             //被标记 ,进入环境
    }
    test();                     //执行完毕 之后 a、b又被标离开环境,被回收。

引用计数

  function test(){
      var a = {} ;         //a的引用次数为0 
      var b = a ;         //a的引用次数加1,为1 
      var c =a;           //a的引用次数再加1,为2
      var b ={};          //a的引用次数减1,为1
  }

内存泄漏

  1. 全局变量

  2. 被遗忘的定时器和回调函数

  3. DOM引用

  4. 闭包引用

     var theThing = null;
     var replaceThing = function () {
       var originalThing = theThing;
       var unused = function () {
         if (originalThing)
           console.log("hi");
       };
       theThing = {
         longStr: new Array(1000000).join('*'),
         someMethod: function () {
           console.log(someMessage);
         }
       };
       unused =null;
     };
     setInterval(replaceThing, 1000);
    

Service Worker 参考文档

6种状态

  1. parsed
  2. installing
  3. installed
  4. activating
  5. activated
  6. redundant

web Worker

为JavaScript 创造多线程环境,

  1. 同源限制,分配给worker线程运行的脚本文件,必须与主线程脚本同源

  2. DOM限制,无法使用document,window,parent,可以使用 navigator,location

  3. 通信联系, 不能直接通信,只能通过消息完成

  4. vue模块化(懒)加载,vue和react的区别、virtual dom、diff算法等问题。

  5. API数据缓存方案。

  6. axios的实现原理。

Service Worker

  1. Service Workers本质上充当Web 应用程序与浏览器之间的代理服务器,也可以在网络可用时作为浏览器和网络间的代理,使得能够创建有效的离线体验,拦截网络请求并基于网络是否可以用以及更新资源是否驻留在服务器上采取适当的动作,允许访问和推送通知到后台同步API

使用Service Worker的条件

  1. 需要在HTTPS中才可以使用serviceWorker
  2. IOS11.3 之后才支持serviceWorker
  3. 如果用户在产品发版后,并且ServiceWorker未主动获取新版本的时段访问站点,用户会使用历史版本,此时需要和确保后端接口兼容历史版本
  4. 要做一些异常情况的应急处理,如主动注销Service Worker

promise、await/async,thunk作用和为什么使用的相同点和不同点。

thunk 参考文档

    1. 传值调用,传名调用
    2. 一种传名调用的实现方式

    function f(m){
      return m * 2;     
    }

    f(x + 5);

    // 等同于

    var thunk = function () {
      return x + 5;
    };

    function f(thunk){
      return thunk() * 2;
    }

    var fs = require('fs');
    var thunkify = require('thunkify');
    var readFile = thunkify(fs.readFile);

    function run(fn) {
      var gen = fn();

      function next(err, data) {
        var result = gen.next(data);
        if (result.done) return;
        result.value(next);
      }

      next();
    }


    var gen = function* (){
      var f1 = yield readFile('./1.json');
      console.dir(f1.toString())
      var f2 = yield readFile('./2.json');
      console.dir(f2.toString())
    };

    run(gen);

使用Promise

    const makeRequest = () =>
    getJSON()
      .then(data => {
        console.log(data)
        return "done"
      })

  makeRequest()

使用Async

    const makeRequest = async() => {
            console.log(await getJSON)
            return "done"
    }

    makeRequest()

区别

  1. 在函数前有一个关键字async,await关键字只能在async定义的函数中使用,如何一个async的函数都会隐式返回一个promise,并且promise reslove 的值就是return 返回的值

  2. 不能在函数开头使用await

  3. Promise有三种状态, reslove,reject, throw, async只有二中reslove throw(reject,throw)

  4. async避免依赖请求的嵌套调用

  5. 错误栈,出错后抛出异常,能清楚的打印到哪里出错

    好处

  6. 代码简介, async让代码看起来更像同步代码,不想Promise 一样需要then

  7. Promise中不能自定义使用 try/catch 进行错误捕获,但是在Async/await中可以

forEach和map的使用场景和区别。forEach中如何break

forEach():

针对每一个元素执行提供的函数

break

  1. throw
  2. 空跑循环
  3. 改原始数组
  4. 该用 every或者some

map():

创建一个新的数组,其中每个元素由调用数组中的每个元素执行提供的函数得来

vscode的技术架构

多进程架构

主进程:VSCode 的入口进程,负责一些类似窗口管理、进程间通信、自动更新等全局任务
渲染进程:负责一个 Web 页面的渲染
插件宿主进程:每个插件的代码都会运行在一个独属于自己的 NodeJS 环境的宿主进程中,插件不允许访问 UI
Debug 进程:Debugger 相比普通插件做了特殊化
Search 进程:搜索是一类计算密集型的任务,单开进程保证软件整体体验与性能

Text Buffer

Document Position

jenkins 的 pipeline as code的语言。(Groovy)

是否使用过webpack搭建项目,loader和plugin的加载顺序。

loader 是一个转换器,将A文件进行编译成B文件,单纯的文件转换过程,针对文件

plugin 是一个扩展器,丰富了webpack本身,针对loader结束后,webpack打包的整个过程,并不是直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,执行广泛的任务,针对工程

项目里UT怎么保证的

和App怎么通信的

常见安全问题

HTTPS咋工作的

React性能咋优化的

深浅拷贝

事件委托

  1. 减少内存消耗(列表事件绑定,事件绑定到父元素,然后用条件判断)

  2. 动态绑定事件

     jquery 
     $.on: 基本用法: $('.parent').on('click', 'a', function () { console.log('click event on tag a'); }),它是 .parent 元素之下的 a 元素的事件代理到 $('.parent') 之上,只要在这个元素上有点击事件,就会自动寻找到 .parent 元素下的 a 元素,然后响应事件;
     $.delegate: 基本用法: $('.parent').delegate('a', 'click', function () { console.log('click event on tag a'); }),同上,并且还有相对应的 $.delegate 来删除代理的事件;
     $.live: 基本使用方法: $('a', $('.parent')).live('click', function () { console.log('click event on tag a'); }),同上,然而如果没有传入父层元素 $(.parent),那事件会默认委托到 $(document) 上;(已废除)
    
  1. 项目中用到了哪些设计模式
  2. Vue双向绑定原理
  3. 对docker的理解
  4. Cookie咋工作的
  5. Chrome Performance用得熟不熟
  6. react vue区别 redux redux-saga场景
  7. 网络安全
  8. 短时间交付大的feature怎么保证质量

状态机

  1. State 状态
  2. Event 事件
  3. Action 动作
  4. Transition 变换