打开全栈工匠技能包-1小时轻松掌握SSR
两小时精通jq+bs插件开发
生产环境下如歌部署Node.js
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
网易内部VUE自定义插件库NPM集成
谁说前端不用懂安全,XSS跨站脚本的危害
webpack的loader到底是什么样的?两小时带你写一个自己loader
-
判断类型是否为原始类型,如果是,无需拷贝,直接返回
-
为避免出现循环引用,拷贝对象时先判断存储空间中是否存在当前对象,如果有就直接返回
-
开辟一个存储空间,来存储当前对象和拷贝对象的对应关系
-
对引用类型递归拷贝直到属性为原始类型
const deepClone = (target, cache = new WeakMap()) => {
if(target === null || typeof target !== ‘object’) {
return target
}
if(cache.get(target)) {
return target
}
const copy = Array.isArray(target) ? [] : {}
cache.set(target, copy)
Object.keys(target).forEach(key => copy[key] = deepClone(obj[key], cache))
return copy
}
深拷贝(尤雨溪版)
vuex源码
- 原理与上一版类似
function find(list, f) {
return list.filter(f)[0]
}
function deepCopy(obj, cache = []) {
// just return if obj is immutable value
if (obj === null || typeof obj !== ‘object’) {
return obj
}
// if obj is hit, it is in circular structure
const hit = find(cache, c => c.original === obj)
if (hit) {
return hit.copy
}
const copy = Array.isArray(obj) ? [] : {}
// put the copy into cache at first
// because we want to refer it in recursive deepCopy
cache.push({
original: obj,
copy
})
Object.keys(obj).forEach(key => copy[key] = deepCopy(obj[key], cache))
return copy
}
函数防抖
-
this
继承自父级上下文,指向触发事件的目标元素 -
事件被触发时,传入
event
对象 -
传入
leading
参数,判断是否可以立即执行回调函数,不必要等到事件停止触发后才开始执行 -
回调函数可以有返回值,需要返回执行结果
const debounce = (fn, wait = 300, leading = true) => {
let timerId, result
return function(…args) {
timerId && clearTimeout(timerId)
if (leading) {
if (!timerId) result = fn.apply(this, args)
timerId = setTimeout(() => timerId = null, wait)
} else {
timerId = setTimeout(() => result = fn.apply(this, args), wait)
}
return result
}
}
函数节流(定时器)
const throttle = (fn, wait = 300) => {
let timerId
return function(…args) {
if(!timerId) {
timerId = setTimeout(() => {
timerId = null
return result = fn.apply(this, …args)
}, wait)
}
}
}
函数节流(时间戳)
const throttle = (fn, wait = 300) => {
let prev = 0
let result
return function(…args) {
let now = +new Date()
if(now - prev > wait) {
prev = now
return result = fn.apply(this, …args)
}
}
}
函数节流实现方法区别
| 方法 | 使用时间戳 | 使用定时器 |
| — | — | — |
| 开始触发时 | 立刻执行 | n秒后执行 |
| 停止触发后 | 不再执行事件 | 继续执行一次事件 |
数组去重
const uniqBy = (arr, key) => {
return […new Map(arr.map(item) => [item[key], item])).values()]
}
const singers = [
{ id: 1, name: ‘Leslie Cheung’ },
{ id: 1, name: ‘Leslie Cheung’ },
{ id: 2, name: ‘Eason Chan’ },
]
console.log(uniqBy(singers, ‘id’))
// [
// { id: 1, name: ‘Leslie Cheung’ },
// { id: 2, name: ‘Eason Chan’ },
// ]
原理是利用Map
的键不可重复
数组扁平化(技巧版)
const flatten = (arr) => arr.toString().split(‘,’).map(item => +item)
数组扁平化
const flatten = (arr, deep = 1) => {
return arr.reduce((cur, next) => {
return Array.isArray(next) && deep > 1 ?
[…cur, …flatten(next, deep - 1)] :
[…cur, next]
},[])
}
函数柯里化
const currying = (fn) {
_curry = (…args) =>
args.length >= fn.length
-
? fn(…args)
- (…newArgs) => _curry(…args, …newArgs)
}
原理是利用闭包把传入参数保存起来,当传入参数的数量足够执行函数时,就开始执行函数
发布订阅EventEmitter
class EventEmitter {
#subs = {}
emit(event, …args) {
if (this.#subs[event] && this.#subs[event].length) {
this.#subs[event].forEach(cb => cb(…args))
}
}
on(event, cb) {
(this.#subs[event] || (this.#subs[event] = [])).push(cb)
}
off(event, offCb) {
if (offCb) {
if (this.#subs[event] && this.#subs[event].length)
this.#subs[event] = this.#subs[event].filter(cb => cb !== offCb)
} else {
this.#subs[event] = []
}
}
}
subs
是EventEmitter
私有属性(最新特性参考阮一峰老师的ECMAScript 6 入门),通过on
注册事件,off
注销事件,emit
触发事件
寄生组合继承
function Super(foo) {
this.foo = foo
}
Super.prototype.printFoo = function() {
console.log(this.foo)
}
function Sub(bar) {
this.bar = bar
Super.call(this)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
ES6版继承
最后
推荐一些系统学习的途径和方法。
每个Web开发人员必备,很权威很齐全的Web开发文档。作为学习辞典使用,可以查询到每个概念、方法、属性的详细解释,注意使用英文关键字搜索。里面的一些 HTML,CSS,HTTP 技术教程也相当不错。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
HTML 和 CSS: