首先什么是memorize函数,memorize直译:记忆,缓存等意思,到了计算机层面就翻译为缓存函数,缓存函数就是把计算的结果,存在函数中,当再次调用的时候就能够直接调用。这种方法就是用空间来换取时间javascript
const memorize = function(fn) { const cache = {} return function(...args) { // 参数值,是一个数组,数组的值是须要计算的值 const _args = JSON.stringify(args) return cache[_args] || (cache[_args] = fn.apply(fn, args)) // 缓存函数的核心判断依据,传入的键名对应的键值为null 则调用add方法 反之从cache中拿取 } } const add = function(a) { return a + 1 } const adder = memorize(add) // memorize只调用一次 后面adder调用的都是return的函数 adder(1) // 2 cache: { '[1]': 2 } adder(1) // 2 cache: { '[1]': 2 } adder(2) // 3 cache: { '[1]': 2, '[2]': 3 }
javascript 权威指南上的解释是: call()、apply()能够看作是某个对象的方法,经过调用方法的形式来间接调用函数。bind()就是将某个函数绑定到某个对象上。前端
var obj = { x:1 } function foo() { console.log(this.x) } foo.call(obj) //1
call()和apply()的第一个参数相同,就是指定对象,他们的根本区别就在于传入的参数。
call传入参数形式为call(obj, 1, 2, 3)
apply传入参数形式为apply(obj, [1,2,3])vue
bind()方法和前二者不一样在于:bind()方法会返回执行上下文被改变的函数,而不会当即执行,而前二者是直接执行该函数。他的参数和call()相同.java
1. 遍历去重 2. json键名不惟一去重 3. new Set()去重
let arr = [1, 2, 3, 4, 5, 6, 7, 7, 7, 3, 111, 1, 3] for (let i = 0; i < arr.length; i++) { for (let j = i + 1; j < arr.length; j++) { if (arr[i] == arr[j]) { arr.splice(j, 1) i = i - 1 } } }
let arr = [1, 2, 3, 4, 5, 6, 7, 7, 7, 3, 111, 1, 3] let obj = {} let result = [] for(let i = 0 ; i < arr.length; i++) { obj[arr[i]] = null } for(let key in obj) { result.push(key) }
let arr = [1, 2, 3, 4, 5, 6, 7, 7, 7, 3, 111, 1, 3] let newArr = new Set(arr) // 返回一个set对象 let result = [] newArr.forEach(val => { result.push(val) })
数组扁平化简单来讲就是把一个多维数组变为一维数组,核心思想:面试
1.递归 2.数值toString() + split() 3.Array.prototype.flat(depth) // Infinity表明无限扁平
递归json
function flatten(arr) { var res = []; arr.map(item => { if(Array.isArray(item)) { res = res.concat(flatten(item)); } else { res.push(item); } }); return res; }
数值的扁平化toString() + split()数组
let arr = [1,2,3,[2,3,4],45,7,[24,[2,3]]] function flatten(arr) { return arr.toString().split(',').map(val => { return Number(val) }) }
flat()缓存
let arr = [1,2,3,[2,3,4],45,7,[24,[2,3]]] arr.flat(infinity)
去抖动和节流,两者都是随着时间推移控制执行函数的次数来达到较少资源消耗,特别在事件触发上,尤其重要。闭包
debounce的做用是,当调用动做触发一段时间后,才会执行该动做,若在这段时间间隔内又调用此动做则将从新计算时间间隔。app
简单来讲就是:调用会一直刷新动做,动做是被延迟执行,直到中止调用等待了一段时间后再执行动做。看下面简单debounce实现节流例子:
function easyDebounce(method, scope) { clearTimeout(method.tId); // onresize会一直被触发,只要在100毫秒内被连续触发计时器都会刷新直到时间大于100毫秒 method.tId= setTimeout(function(){ method.call(scope); }, 100); } function resizeDiv(){ var div = document.getElementById("myDiv"); div.style.height = div.offsetWidth + "px"; } // 节流在resize事件中最经常使用 window.onresize = function(){ easyDebounce(resizeDiv); };
throttle预先设定一个执行周期,当调用动做的时刻大于等于执行周期则执行该动做,而后进入下一个新的时间周期。throttle能够基于debounce实现,只须要加上一个阀值(最小值)若是时间小于定义的阀值 则不触发动做,大于则触发并刷新周期,并且第一次一定触发。节流不实用定时器,debounce使用定时器
var throttleV2 = function(action, delay){ var statTime = 0; return function() { // 每次resize执行的函数 闭包保证statTime能够一直使用 var currTime = +new Date(); if (currTime - statTime > delay) { action.apply(this, arguments); statTime = currTime ; // 每次调用完以后刷新时间 } } } // example function resizeHandler() { console.log("resize"); } window.onresize = throttleV2(resizeHandler, 300);
vue实现数据的双向绑定根本API是Object.defineProperty(),经过这个方法重写get,和set属性来达到数据双向绑定
详细解读一下Object.defineProperty()这个东西到底干了啥
var Book = {} var name = ''; Object.defineProperty(Book, 'name', { set: function (value) { name = value; console.log('书名:' + value); }, get: function () { return '《' + name + '》' } }) Book.name = '前端学习'; console.log(Book.name);
双向绑定是用发布订阅模式实现,因此涉及到监听器Observer、订阅者Watcher、解析器Compile,以及消息订阅器dep收集watcher。
图片来自互联网:
vue scoped的实现是经过在对应的dom节点添加data-v-哈希值,并在style每一个属性后面加上这串data-v-hash来实现样式的惟一性,起到一个样式做用域的效果。
可是实际应用中添加scoped也会带来一些麻烦,好比设置完scoped属性以后没法修改子组件的样式。再次有两点供你们参考:
持续更新中~~~