首页
前端面试题
前端报错总结
电子书
更多
插件下载
Search
1
JavaScript基础(二)操作符 流程控制
42 阅读
2
HTML基础
20 阅读
3
Vue基础
17 阅读
4
wctype.h
14 阅读
5
Vue2(知识点)
13 阅读
默认分类
HTML CSS
HTML基础
CSS
HTML5 CSS3
javaScript
javaScript基础
javaScript高级
Web APIs
jQuery
js小总结
WEB开发布局
Vue
PS切图
数据可视化
Git使用
Uniapp
c语言入门
标准库
嵌入式
登录
Search
liuxiaobai
累计撰写
108
篇文章
累计收到
12
条评论
首页
栏目
默认分类
HTML CSS
HTML基础
CSS
HTML5 CSS3
javaScript
javaScript基础
javaScript高级
Web APIs
jQuery
js小总结
WEB开发布局
Vue
PS切图
数据可视化
Git使用
Uniapp
c语言入门
标准库
嵌入式
页面
前端面试题
前端报错总结
电子书
插件下载
搜索到
7
篇与
的结果
2021-09-12
js小技巧
{mtitle style='font-size:25px' title="数组扁平化"/}数组扁平化是将一个多维数组变为一个一维数组:const arr = [1, [2, [3, [ 4,5 ]]],6 ] // => [1,2,3,4,5,6]方法一:使用flat()const arr = [1, [2, [3, [ 4,5 ]]],6 ] // => [1,2,3,4,5,6] const res1 = arr.flat(Infinity);方法二:利用正则const arr = [1, [2, [3, [ 4,5 ]]],6 ] // => [1,2,3,4,5,6] const res2 = JSON.stringify(arr).replace(/\[|\]/g,'').split(',');注:但数据类型都会变为字符串方法三:正则改良版本const arr = [1, [2, [3, [ 4,5 ]]],6 ] // => [1,2,3,4,5,6] const res3 = JSON.parse('[' + JSON.stringify(arr).replace(/\[|\]/g,'') + ']');方法四:使用reduceconst arr = [1, [2, [3, [ 4,5 ]]],6 ] // => [1,2,3,4,5,6] const flatten = arr => { return arr.reduce((pre, cur) => { return pre.concat(Array.isArray(cur) ? flatten(cur) : cur); }, []) } const res4 = flatten(arr)方法五:函数递归const arr = [1, [2, [3, [ 4,5 ]]],6 ] // => [1,2,3,4,5,6] const res5 = []; const fn = arr => { for (let i = 0; i < arr.length; i++){ if (Array.isArray(arr[i])) { fn(arr[i]); } else { res5.push(arr[i]); } } } fn(arr);{mtitle style='font-size:25px' title="数组去重"/}代码和处理后结果如下:const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}]; // => [1, '1', 17, true, false, 'true', 'a', {}, {}]方法一:利用Setconst arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}]; // => [1, '1', 17, true, false, 'true', 'a', {}, {}] const res1 = Array.from(new Set(arr));方法二:双层for循环+spliceconst arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}]; // => [1, '1', 17, true, false, 'true', 'a', {}, {}] const unique1 = arr => { let len = arr.length; for (let i = 0; i < len; i++) { for (let j = i + 1; j < len; j++) { if (arr[i] === arr[j]){ arr.splice(j ,1); //每删除一个数,j--保证j的值经过自加后不变。同时,len--,减少循环次数提升性能 len--; j--; } } } return arr; }方法三:利用indexOfconst arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}]; // => [1, '1', 17, true, false, 'true', 'a', {}, {}] const unique2 = arr => { const res = []; for (let i = 0; i < arr.length; i++) { if (res.indexOf(arr[i]) === -1) res.push(arr[i]); } return res; }方法四:利用includeconst arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}]; // => [1, '1', 17, true, false, 'true', 'a', {}, {}] const unique3 = arr => { const res = []; for (let i = 0; i < arr.length; i++) { if (!res.includes(arr[i])) res.push(arr[i]); } return res; }方法五:利用filterconst arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}]; // => [1, '1', 17, true, false, 'true', 'a', {}, {}] const unique4 = arr => { return arr.filter((item, index) => { return arr.indexOf(item) === index; }); }方法六:利用Mapconst arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}]; // => [1, '1', 17, true, false, 'true', 'a', {}, {}] const unique5 = arr => { const map = new Map(); const res = []; for (let i = 0; i < arr.length; i++) { if(!map.has(arr[i])) { map.set(arr[i], true) res.push(arr[i]); } } return res; }{mtitle style='font-size:25px' title="类数组转化为数组"/}类数组是具有length属性,但不具有数组原型上的方法。常见的类数组有arguments、DOM操作方法返回的结果。方法一:Array.fromArray.from(document.querySelectorAll('div'))方法二:Array.prototype.slice.call()Array.prototype.slice.call(document.querySelectorAll('div'))方法三:扩展运算符[...document.querySelectorAll('div')]方法四:利用concatArray.prototype.apply([], document.querySelectorAll('div')){mtitle style='font-size:25px' title="Array.prototype.filter()"/}语法:var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])参数callback用来测试数组的每个元素的函数。返回 true 表示该元素通过测试,保留该元素,false 则不保留。它接受以下三个参数: element 数组中当前正在处理的元素。 index可选 正在处理的元素在数组中的索引。 array可选 调用了 filter 的数组本身。thisArg可选执行 callback 时,用于 this 的值。返回值一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。Array.prototype.filter = function(callback, thisArg) { if (this == undefined) { throw new TypeError('this is null or not undefined'); } if (typeof callback !== 'function') { throw new TypeError(callback + 'is null or not undefined'); } const res = []; // 让o成为回调函数的对象传递(强制转换对象) const o = Object(this); // >>>0 保证len为number,且为正整数 const len = o.length >>> 0; for (let i = 0; i < len; i++) { // 检查i是否在o的属性(会检查原型链) if (i in o) { // 回调函数调用传参 if (callback.call(thisAry, o[i], i, o)) { res.push(o[i]); } } } return res; }{mtitle style='font-size:25px' title="Array.prototype.map()"/}语法:var new_array = arr.map(function callback(currentValue[, index[, array]]) { // 返回一个新数组 }[, thisArg])参数callback生成新数组元素的函数,使用三个参数: currentValue callback 数组中正在处理的当前元素。 index可选 callback 数组中正在处理的当前元素的索引。 array可选 map 方法调用的数组。thisArg可选执行 callback 函数时值被用作this。返回值一个由原数组每个元素执行回调函数的结果组成的新数组。Array.prototype.map = function(callback, thisArg) { if (this == undefined) { throw new TypeError('this is null or not undefined'); } if (typeof callback !== 'function') { throw new TypeError(callback + 'is null or not undefined'); } const res = []; // 让o成为回调函数的对象传递(强制转换对象) const o = Object(this); // >>>0 保证len为number,且为正整数 const len = o.length >>> 0; for (let i = 0; i < len; i++) { // 检查i是否在o的属性(会检查原型链) if (i in o) { // 回调函数调用传参 res[i] = callback.call(thisAry, o[i], i , this); } } return res; }{mtitle style='font-size:25px' title="Array.prototype.forEach()"/}语法myMap.forEach(callback([value][,key][,map])[, thisArg])参数callbackmyMap 中每个元素所要执行的函数。它具有如下的参数: value 可选 每个迭代的值。 key 可选 每个迭代的键。 map 可选 被迭代的map(上文语法框中的 myMap)。thisArg 可选在 callback 执行中使用的 this 的值。返回值undefined. forEach跟map类似,唯一不同的是forEach是没有返回值的。 Array.prototype.forEach = function(callback, thisArg) { if (this == null) { throw new TypeError('this is null or not undefined'); } if (typeof callback !== 'function') { throw new TypeError(callback + 'is null or not undefined'); } // 让o成为回调函数的对象传递(强制转换对象) const o = Object(this); // >>>0 保证len为number,且为正整数 const len = o.length >>> 0; let k = 0; while(k < len){ if(k in o){ callback.call(thisArg, o[k], k, o); } k++; } }{mtitle style='font-size:25px' title="Array.prototype.reduce()"/}语法arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])参数callback执行数组中每个值 (如果没有提供 initialValue则第一个值除外)的函数,包含四个参数: accumulator 累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。 currentValue 数组中正在处理的元素。 index 可选 数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则从索引1起始。 array可选 调用reduce()的数组initialValue可选作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。返回值函数累计处理的结果Array.prototype.forEach = function(callback, thisArg) { if (this == undefined) { throw new TypeError('this is null or not undefined'); } if (typeof callback !== 'function') { throw new TypeError(callback + 'is null or not undefined'); } // 让o成为回调函数的对象传递(强制转换对象) const o = Object(this); // >>>0 保证len为number,且为正整数 const len = o.length >>> 0; let accumulator = initialValue; let k = 0; //如果第二个参数为undefined的情况下 //则数组的第一个有效值最为累加器的初始值 if(accumulator === undefined) { while(k < len && !(k in o)) { k++; //如果超出数组界限还没有找到累加器的初始值,则TypeError if(k >=len) { throw new TypeError('Reduce of empty array with on initial value'); } accumulator = o[k++]; } while (k < len) { if(k in o){ accumulator = callback.call(undefined, accumulator, o[k], k ,o); } k++; } return accumulator; }{mtitle style='font-size:25px' title="Array.prototype.apply()"/}第一个参数是绑定的this,默认为window,第二个参数是数组或类数组。Function.prototype.apply= function(context=window, args){ if(typeof this !== 'function') { throw new TypeError('Type Error'); } const fn = Symbol('fn'); context[fn] = this; const res = context[fn](...args); delete context[fn]; return res; }{mtitle style='font-size:25px' title="Array.prototype.call()"/}注意:该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。Function.prototype.call= function(context=window, ...args){ if(typeof this !== 'function') { throw new TypeError('Type Error'); } const fn = Symbol('fn'); context[fn] = this; const res = context[fn](...args); delete context[fn]; return res; }{mtitle style='font-size:25px' title="Array.prototype.bind()"/}bind() 函数会创建一个新的绑定函数(bound function,BF)。绑定函数是一个 exotic function object(怪异函数对象,ECMAScript 2015 中的术语),它包装了原函数对象。调用绑定函数通常会导致执行包装函数。Function.prototype.bind= function(context, ...args){ if(typeof this !== 'function') { throw new Error('Type Error'); } // 保存this的值 var self = this; return function F(){ //考虑new的情况 if(this instanceof F){ return new self(...args, ...arguments) } return self.apply(context,[...args, ...arguments]) } }{mtitle style='font-size:25px' title="debounce(防抖)"/}触发高频时间后n秒内函数只会执行一次,如果n秒内高频时间再次触发,则重新计算时间const debounce = (fn, time) => { let timeout = null; return function() { clearTimeout(timeout); timeout = setTimeout(() => { fn.apply(this, arguments); }, time); } }{mtitle style='font-size:25px' title="throttle(节流)"/}高频时间触发,但n秒内只会执行一次,所以节流会稀释函数的执行频率。const throttle = (fn, time) => { let flag = true; return function() { if (!flag) return; flag = false; setTimeout(() => { fn.apply(this, arguments); flag = true; } , time); } } //第二种写法 非定时器写法 function fun(fn,time){ var activeTime=0 return ()=>{ var current =new Date() if(current-activeTime>time){ fn.apply(this,arguments) activeTime=new Date() } } }注: 节流常应用于鼠标不断点击触发 、 监听滚动事件{mtitle style='font-size:25px' title="函数柯理化"/}指的是将一个接受多个参数的函数变为接受一个参数返回一个函数的固定形式,这样便于再次调用,列如f(1)(2)。经典面试题:实现add(1)(2)(3)(4)=10;、add(1)(1,2,3)(2)=9function add() { const _args = [...arguments]; function fn() { _args.push(...arguments); return fu; } fn.toString = function() { return _args.reduce((sum, cur) => sum + cur); } return fn; }{mtitle style='font-size:25px' title="模拟new操作"/}3个步骤:以ctor.prototype为原型创建一个对象。执行构造函数并将this绑定到新创建的对象上。判断构造函数执行返回的结果是否引用数据类型,若是则返回构造函数执行的结果,否则返回创建的对象。function newOperator(ctor, ...args) { if (typeof ctor !== 'function') { throw new TypeError('Type Error'); } const obj = Object.create(ctor.prototype); const res = ctor.apply(obj, args); const isObject = typeof res === 'object' && res !== null; const isFunction = typeof res === 'function'; return isObject || isFunction ? res : obj; }{mtitle style='font-size:25px' title="instanceof"/}instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上const myInstanceof = (left, right) => { //基于数据类型都返回false if (typeof left !== 'object' || left === null) return false; let proto = Object.getPrototypeOf(left); while (true) { if (proto === null) return false; if (proto === right.prototype) return true; proto = Object.getPrototypeOf(proto); } }{mtitle style='font-size:25px' title="原型继承"/}这里只写寄生组合继承了,中间还有几个演变过来的继承但是有一定缺陷。function Parent(){ this.name='parent'; } function Child(){ Parent.call(this); this.type='children'; } Child.prototype=Object.create(Parent.prototype); Child.prototype.constructor=Child;{mtitle style='font-size:25px' title="Object.is"/}Object.is解决的主要的这两个问题+0 === -0 //true NaN === NaN //false const is = (x, y) => { if (x === y) { // +0和-0应该不相等 return x !== 0 || y !== 0 || 1 / x === 1 / y; } else { return x !== x && y !== y; } }{mtitle style='font-size:25px' title="Object.assign"/}Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象(请注意这个操作是浅拷贝)Object.defineProperty(Object, 'assign', { value: function(target, ...args) { if (target == null) { return new TypeError('Cannot convert undefined or null to object'); } //目标对象需要统一是引用数据类型,若不是会自动转换。 const to = Object(target); for (let i = 0; i < args.length; i++) { //每一个源对象 const nextSource = args[i]; if (nextSource !== null) { //使用for...in和hasOwnProperty双重判断,确保只拿到本身属性,方法(不包含继承的) for (const nextKey in nextSource) { if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; } } } } return to; }, //不可枚举 enumerable:false, writable:true, configurable:true, }){mtitle style='font-size:25px' title="深拷贝"/}递归的完整版本(考虑到了Symbol属性)const cloneDeep1 = (target, hash = new WeakMap()) => { //对于传入参数处理 if (typeof target !== 'object' || target === null) { return target; } //哈希表中存在直接返回 if (hash.has(target)) return hash.get(target); const cloneTarget = Array.isArray(target) ? [] : {}; hash.set(target, cloneTarget); //针对Symbol属性 const symKeys = Object.getOwnPropertySymbols(target); if (symKeys.length) { symKeys.forEach(Symbol => { if (typeof target[symKeys] === 'object' && target[symKeys] !== null) { cloneTarget[symKeys] = cloneDeep1(target[symKeys]); } else { cloneTarget[symKeys] = target[symKeys]; } }) } for (const i in target) { if (Object.prototype.hasOwnProperty.call(target, i)) { cloneTarget[i] = typeof target[i] === 'object' && target[i] !== null ? cloneDeep1(target[i].hash) : target[i] } } return cloneTarget; }{mtitle style='font-size:25px' title="Promise"/}
2021年09月12日
5 阅读
0 评论
0 点赞
1
2
3