共计 12215 个字符,预计需要花费 31 分钟才能阅读完成。
1、确定任意对象的具体类型家喻户晓,JavaScript 中有六种原始数据类型(Boolean、Number、String、Null、Undefined、Symbol)和一个对象数据类型。然而你晓得对象数据类型能够细分为很多种子类型吗?一个对象可能是数组、函数、map 等,如果咱们要获取对象的具体类型,应该怎么做呢?代码:function toRawType (value) {let _toString = Object.prototype.toString; let str = _toString.call(value) return str.slice(8, -1)} 解释 ECMAScript 有以下规定:
对于不同的对象,调用 Object.prototype.toString() 时会返回不同的后果。
而且,Object.prototype.toString() 的返回值总是‘[object’+‘tag’+‘]’的格局。如果咱们只想要两头的标签,咱们能够通过正则表达式或者 String.prototype.slice() 删除两边的字符。例子:toRawType(null) // “Null”toRawType(/sdfsd/) //”RegExp”2、缓存函数计算结果如果有这样的性能:function computed(str) {// Suppose the calculation in the funtion is very time consuming console.log(‘2000s have passed’) return ‘a result’} 咱们要缓存函数操作的后果,稍后调用时,如果参数雷同,则不再执行该函数,而是间接返回缓存中的后果。咱们能做什么?代码:function cached(fn){// Create an object to store the results returned after each function execution. const cache = Object.create(null); // Returns the wrapped function return function cachedFn (str) {// If the cache is not hit, the function will be executed if ( !cache[str] ) {let result = fn(str); // Store the result of the function execution in the cache cache[str] = result; } return cache[str] }} 例子:
3、实现 Array.prototype.map 这是 JavaScript 中一个有用的内置办法,你应该可能本人实现此性能。代码:const selfMap = function (fn, context) {let arr = Array.prototype.slice.call(this) let mappedArr = Array() for (let i = 0; i < arr.length; i++) {if (!arr.hasOwnProperty(i)) continue; mappedArr[i] = fn.call(context, arr[i], i, this) } return mappedArr}Array.prototype.selfMap = selfMap; 例子:
4、实现 Array.prototype.filter 这是 JavaScript 中一个有用的内置办法,你应该可能本人实现此性能。代码:const selfFilter = function (fn, context) {let arr = Array.prototype.slice.call(this) let filteredArr = [] for (let i = 0; i < arr.length; i++) {if(!arr.hasOwnProperty(i)) continue; fn.call(context, arr[i], i, this) && filteredArr.push(arr[i]) } return filteredArr}Array.prototype.selfFilter = selfFilter; 例子:
5、实现 Array.prototype.some 这是 JavaScript 中一个有用的内置办法,你应该可能本人实现此性能。代码:const selfSome = function (fn, context) {let arr = Array.prototype.slice.call(this) if(!arr.length) return false for (let i = 0; i < arr.length; i++) {if(!arr.hasOwnProperty(i)) continue; let res = fn.call(context,arr[i],i,this) if(res)return true } return false}Array.prototype.selfSome = selfSome; 例子:
6、实现 Array.prototype.reduce 这是 JavaScript 中一个有用的内置办法,你应该可能本人实现此性能。代码:const selfReduce = function (fn, initialValue) {let arr = Array.prototype.slice.call(this) let res let startIndex if (initialValue === undefined) {for (let i = 0; i < arr.length; i++) {if (!arr.hasOwnProperty(i)) continue startIndex = i res = arr[i] break } } else {res = initialValue} for (let i = ++startIndex || 0; i < arr.length; i++) {if (!arr.hasOwnProperty(i)) continue res = fn.call(null, res, arr[i], i, this) } return res}Array.prototype.selfReduce = selfReduce; 例子:
7、实现 Array.prototype.flat 代码:const selfFlat = function (depth = 1) {let arr = Array.prototype.slice.call(this) if (depth === 0) return arr return arr.reduce((pre, cur) => {if (Array.isArray(cur)) {return […pre, …selfFlat.call(cur, depth – 1)] } else {return […pre, cur] } }, [])}Array.prototype.selfFlat = selfFlat; 例子:
8、柯里化柯里化是一种将具备多个参数的函数评估为具备单个参数的函数序列的技术。换句话说,当一个函数不是一次承受所有参数时,而是承受第一个参数并返回一个新函数,该函数承受第二个参数并返回一个新函数,该函数承受第三个参数,依此类推,直到所有参数都已履行。那就是咱们将函数调用 add(1,2,3) 转换为 add(1)(2)(3)。通过应用这种技术,能够轻松地配置和重用小块。为什么有用?柯里化能够帮忙您防止一次又一次地传递雷同的变量。它有助于创立高阶函数,它对事件处理十分有帮忙。小部件能够轻松配置和重用。让咱们看一个简略的增加函数。它承受三个操作数作为参数,并返回所有三个操作数的总和作为后果。function add(a,b,c){return a + b + c;} 你能够用太少(后果奇怪)或太多(多余的参数被疏忽)来调用它。add(1,2,3) –> 6 add(1,2) –> NaNadd(1,2,3,4) –> 6 //Extra parameters will be ignored. 如何将现有函数转换为 curried 版本?代码:function curry(fn) {if (fn.length <= 1) return fn; const generator = (…args) => {if (fn.length === args.length) {return fn(…args) } else {return (…args2) => {return generator(…args, …args2) } } } return generator} 例子:
9、去抖动去抖动只不过是缩小不必要的耗时计算,以进步浏览器性能。在某些状况下,某些性能须要更多工夫来执行某个操作。例如,以电子商务网站上的搜寻栏为例。假如用户想要取得“Tutorix 学习套件”。他在搜寻栏中键入产品的每个字符。输出每个字符后,从浏览器到服务器都会进行一次 Api 调用,以获取所需的产品。因为他想要“Tutorix 学习套件”,用户必须从浏览器到服务器进行 17 次 Api 调用。设想一个场景,当数百万人进行雷同的搜寻从而调用数十亿个 Api 时。所以一次调用数十亿个 Api 必定会导致浏览器性能变慢。为了缩小这个毛病,去抖动呈现了。在这种状况下,去抖动将在两次击键之间设置一个工夫距离,假如为 2 秒。如果两次击键之间的工夫超过 2 秒,则只会进行 Api 调用。在这 2 秒内,用户能够输出至多一些字符,从而缩小 Api 调用的这些字符。因为 Api 调用缩小,浏览器性能将进步。必须留神,每次击键都会更新 Debouncing 性能。代码:const debounce = (func, time = 17, options = { leading: true, context: null}) => {let timer; const _debounce = function (…args) {if (timer) {clearTimeout(timer) } if (options.leading && !timer) {timer = setTimeout(null, time) func.apply(options.context, args) }else{timer = setTimeout(() => {func.apply(options.context, args) timer = null }, time) } }; _debounce.cancel = function () { clearTimeout(timer) timer = null }; return _debounce};10、节流节流将以这样一种形式更改函数,即它能够在一个工夫距离内最多触发一次。例如,无论用户单击按钮多少次,限度将在 1000 毫秒内仅执行一次该性能。
代码:const throttle = (func, time = 17, options = { leading: true, trailing: false, context: null}) => {let previous = new Date(0).getTime() let timer; const _throttle = function (…args) {let now = new Date().getTime(); if (!options.leading) {if (timer) return timer = setTimeout(() => { timer = null func.apply(options.context, args) }, time) } else if (now – previous > time) {func.apply(options.context, args) previous = now } else if (options.trailing) {clearTimeout(timer) timer = setTimeout(() => { func.apply(options.context, args) }, time) } }; _throttle.cancel = () => { previous = 0; clearTimeout(timer); timer = null }; return _throttle};11、提早加载图片提早加载图片意味着在网站上异步加载图片——也就是说,在首屏内容齐全加载之后,甚至有条件地,只有当它们呈现在浏览器的视口中时。这意味着如果用户不始终向下滚动,则搁置在页面底部的图像甚至不会被加载。代码:// getBoundingClientRectlet imgList1 = […document.querySelectorAll(“.get_bounding_rect”)]let num = imgList1.lengthlet lazyLoad1 = (function () {let count = 0 return function () {let deleteIndexList = [] imgList1.forEach((img,index) => {let rect = img.getBoundingClientRect() if (rect.top < window.innerHeight) {img.src = img.dataset.src // Add picture to delete list after loading successfully deleteIndexList.push(index) count++ if (count === num) {//When all pictures are loaded, unbind scroll event document.removeEventListener(‘scroll’,lazyLoad1) } } }) // Delete loaded pictures imgList1 = imgList1.filter((_,index)=>!deleteIndexList.includes(index)) }})()12、数组随机无序咱们常常须要打乱一个数组。代码:// Randomly select one of all elements after the current element to exchange with the current elementfunction shuffle(arr) {for (let i = 0; i < arr.length; i++) {let randomIndex = i + Math.floor(Math.random() (arr.length – i)); [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]] } return arr}// Generate a new array, randomly take an element from the original array and put it into the new arrayfunction shuffle2(arr) {let _arr = [] while (arr.length) {let randomIndex = Math.floor(Math.random() (arr.length)) _arr.push(arr.splice(randomIndex, 1)[0]) } return _arr} 例子:
13、单例模式单例模式将特定对象的实例数限度为一个,这个繁多实例称为单例模式。单例在须要从单个核心地位协调系统范畴的操作的状况下很有用。一个例子是数据库连接池。池治理整个应用程序的所有数据库连贯的创立、销毁和生命周期,确保没有连贯“失落”。单例缩小了对全局变量的需要,这在 JavaScript 中尤为重要,因为它限度了命名空间净化和相干的名称抵触危险。代码:function proxy(func) {let instance; let handler = { construct(target, args) {if (!instance) {// Create an instance if there is not exist instance = Reflect.construct(func,args) } return instance } } return new Proxy(func, handler)}// examplefunction Person(name, age) {this.name = name this.age = age}const SingletonPerson = proxy(Person)let person1 = new SingletonPerson(‘zhl’, 22)let person2 = new SingletonPerson(‘cyw’, 22)console.log(person1 === person2) // true 例子:
14、实现 JSON.stringify 这是 JavaScript 中一个有用的内置办法,你应该可能本人实现此性能。代码:const isString = value => typeof value === ‘string’;const isSymbol = value => typeof value === ‘symbol’const isUndefined = value => typeof value === ‘undefined’const isDate = obj => Object.prototype.toString.call(obj) === ‘[object Date]’const isFunction = obj => Object.prototype.toString.call(obj) === ‘[object Function]’;const isComplexDataType = value => (typeof value === ‘object’ || typeof value === ‘function’) && value !== null;const isValidBasicDataType = value => value !== undefined && !isSymbol(value); const isValidObj = obj => Array.isArray(obj) || Object.prototype.toString.call(obj) === ‘[object Object]’;const isInfinity = value => value === Infinity || value === -Infinity// Symbol,undefined,function in array will become null// Infinity,NaN will also become nullconst processSpecialValueInArray = value => isSymbol(value) || isFunction(value) || isUndefined(value) || isInfinity(value) || isNaN(value) ? null : value;// Handling property values according to JSON specificationconst processValue = value => {if (isInfinity(value) || isNaN(value)) {return null} if (isString(value)) {return "${value}"
} return value};// obj.loop = objconst jsonStringify = (function () {// Closure + WeakMap prevent circular references let wp = new WeakMap(); //It is the function in the closure that recursively calls jsonstrify, not the jsonstrify function declared by const return function jsonStringify(obj) {if (wp.get(obj)) throw new TypeError(‘Converting circular structure to JSON’); let res = “”; if (isComplexDataType(obj)) {if (obj.toJSON) return obj.toJSON; if (!isValidObj(obj)) {return} wp.set(obj, obj); if (Array.isArray(obj)) {res += “[“; let temp = []; obj.forEach((value) => {temp.push( isComplexDataType(value) && !isFunction(value) ? jsonStringify(value) : ${processSpecialValueInArray(value, true)}
) }); res += ${temp.join(',')}]
} else {res += “{“; let temp = []; Object.keys(obj).forEach((key) => {if (isComplexDataType(obj[key])) {if (isValidObj(obj[key])) {temp.push("${key}":${jsonStringify(obj[key])}
) } else if (isDate(obj[key])) {temp.push("${key}":"${obj[key].toISOString()}"
) } else if (!isFunction(obj[key])) {temp.push("${key}":{}
) } } else if (isValidBasicDataType(obj[key])) {temp.push("${key}":${processValue(obj[key])}
) } }); res += ${temp.join(',')}}
} } else if (isSymbol(obj)) {return} else {return obj} return res }})();// examplelet s = Symbol(‘s’)let obj = {str: “123”, arr: [1, {e: 1}, s, () => {}, undefined,Infinity,NaN], obj: {a: 1}, Infinity: -Infinity, nan: NaN, undef: undefined, symbol: s, date: new Date(), reg: /123/g, func: () => {}, dom: document.querySelector(‘body’),};console.log(jsonStringify(obj));console.log(JSON.stringify(obj)); 例子:
总结以上就是我与你分享的 14 个 JavaScript 的函数,这些函数也是咱们作为一名 web 前端开发人员必须要晓得的,心愿对你有用,如果感觉对你有帮忙的话,请记得点赞我,关注我,并将它分享给你身边做开发的敌人,兴许可能帮忙到他。