www.91084.com

GVKun编程网logo

41个Web开发者必须收藏的JavaScript实用技巧

15

在本文中,我们将带你了解41个Web开发者必须收藏的JavaScript实用技巧在这篇文章中,同时我们还将给您一些技巧,以帮助您实现更有效的10个适用于JavaScript开发的IDE新功能|实用技巧

在本文中,我们将带你了解41个Web开发者必须收藏的JavaScript实用技巧在这篇文章中,同时我们还将给您一些技巧,以帮助您实现更有效的10 个适用于 JavaScript 开发的 IDE 新功能 | 实用技巧、20 个值得收藏的实用 JavaScript 技巧、2020最新JavaScript开发必须知道的41个技巧,你会几个?、21个值得收藏的Javascript技巧

本文目录一览:

41个Web开发者必须收藏的JavaScript实用技巧

41个Web开发者必须收藏的JavaScript实用技巧

Web开发者必须收藏的JavaScript实用技巧,供大家参考,具体内容如下

1. 将彻底屏蔽鼠标右键

oncontextmenu=”window.event.returnValue=false”

< table border oncontextmenu=return(false)>< td>no< /table> 可用于 Table

2. 取消选取、防止复制

< body onselectstart=”return false”>

3.JS不允许粘贴

onpaste=”return false”

4. JS防止复制

oncopy=”return false;” oncut=”return false;”

5. IE 地址栏前换成自己的图标

< link rel=”Shortcut Icon” href=”favicon.ico”> 在文件的根目录放进去这个图片,后缀修改成ico就可以了

6.可以在收藏夹中显示出你的图标

< link rel=”Bookmark” href=”favicon.ico”>

7.关闭输入法

< input style=”ime-mode:disabled”>

8. 永远都会带着框架

< script language=”JavaScript”>< !–

if (window == top)top.location.href = “frames.htm”; //frames.htm 为框架网页

// –>< /script>

9. 防止被人 frame

< SCRIPT LANGUAGE=JAVASCRIPT>< !–

if (top.location != self.location)top.location=self.location;

// –>< /SCRIPT>

10. 网页将不能被另存为

< noscript>< iframe src=*.html>< /iframe>< /noscript>

11. < input type=button value=查看网页源代码

onclick=”window.location = “view-source:”+ “http://www.pconline.com.cn””>

12. 删除时确认

< a href=”javascript:if(confirm(” 确 实 要 删 除 吗 ?”))location=”boos.asp?&areyou= 删 除

&page=1″”>删除< /a>

13. 取得控件的绝对位置

<div>
<prehttps://www.jb51.cc/tag/rush/" target="_blank">rush:js;">
//Javascript

< script language=”Javascript”> function getIE(e){ var t=e.offsetTop; var l=e.offsetLeft; while(e=e.offsetParent){ t+=e.offsetTop; l+=e.offsetLeft; } alert(“top=”+t+”/nleft=”+l); } < /script>

//VBScript

< script language=”VBScript”>< !– function getIE() dim t,l,a,b set a=document.all.img1 t=document.all.img1.offsetTop l=document.all.img1.offsetLeft while a.tagName< >”BODY” set a = a.offsetParent t=t+a.offsetTop l=l+a.offsetLeft wend msgBox “top=”&t&chr(13)&”left=”&l,64,”得到控件的位置” end function –>< /script>

10 个适用于 JavaScript 开发的 IDE 新功能 | 实用技巧

10 个适用于 JavaScript 开发的 IDE 新功能 | 实用技巧

JetBrains IDE 中的功能数不胜数,有些实用功能虽然能让开发者更轻松、更有效率地工作,却也很容易被忽略。


今天的博文中,我们将为在 WebStorm 和其他 JetBrains IDE 中使用 JavaScript 和相关技术的人,介绍近期添加的一些可以提高工作效率的最实用功能。



Code With Me


去年,我们推出了令人期待的 Code With Me,收到了大家的积极反馈。这是一项用于协作开发的新 JetBrains 服务。您可以使用它在 IDE 中与协作者共同编写代码和实时交流。它也支持视频通话!


如果您还没有尝试,现在绝对是最佳时机。查看我们的文档,阅读 Code With Me 使用入门,以及查找一些常见问题的答案。



用于更新依赖项的新检查


现在,可以直接从编辑器将 npm 软件包更新到最新版本。只需打开 package.json 文件,将文本光标放在要更新的软件包版本上,按 ⌥⏎ / Alt+Enter ,然后选择Update ‘package name’ to the latest version(将“软件包名称”更新到最新版本)。


您可以为检查添加不同的高亮显示,用来明确哪些软件包需要更新。要更改高亮显示,首先转到 Preferences / Settings | Editor | Inspections | JavaScript and TypeScript | Imports and dependencies | Update package.json dependencies to latest versions(偏好设置/设置 | 编辑器 | 检查 | JavaScript 和 TypeScript | Import 和依赖项 | 将 package.json 依赖项更新到最新版本),然后选择需要的 Severity(严重性)选项。此外,将鼠标悬停在软件包版本上时,您将获得快速修复。




对 package.json 中 imports 和

exports 字段的支持



在 JavaScript 中使用相对 import 可能比较麻烦。可读 import 更为实用。借助在 Node.js 14.13.0 中引入的import字段,您可以使用快捷键导入本地模块,避免相对路径,不存在与现有软件包冲突的任何风险。我们已确保为 IDE 中的import语句实现导航、解析、自动导入和代码补全支持



内置 HTML 预览和保存时重新加载


为了查看更改的效果,先要保存 HTML 页面,然后在浏览器中刷新,这样的过程可能不够理想。现在,您可以直接在 IDE 中预览静态 HTML 文件。


您还可以使用内置 Web 服务器在浏览器中预览 HTML 文件。为此,请点击要使用的浏览器的图标。


默认情况下,每当您保存 HTML 文件或与其关联的 JavaScript 和样式表文件时,IDE 都会自动重新加载预览或浏览器页面。如果您想一边进行更改一边查看更改,可以更改默认行为。只需前往 Preferences / Settings | Tools | Web Browsers and Preview(偏好设置/设置 | 工具 | Web 浏览器和预览),选择 On Change(更改时)而不是 On Save(保存时)。



.js 与 .d.ts 文件之间更好的映射


另一个方便的改进涉及.js.d.ts文件。我们改进了它们之间的映射,并添加了间距图标以实现更好的导航。阅读这篇博文,详细了解更改,或在下方 GIF 中查看它们的实际运作情况。




private 字段的 

Rename(重命名)重构



技术变革可能会发生得很快,而我们始终将全力提供支持。在这里,我们添加了 Rename(重命名)重构,通过#将字段设为 private,您就可以将实现细节隐藏起来。我们将实现与规范保持一致,使用更好的重构支持 private 字段。IDE 也理解此语法,会在您创建了在类外使用的 private 类成员时发出警告。



提取 Angular 组件重构


从 Vue 和 React 提取组件的选项已经推出一段时间了。借助 Extract Component(提取组件)重构,您可以从现有组件中提取新组件,无需任何复制粘贴。去年,我们也为 Angular 引入了类似的功能。要开始试用,首先选择要提取的 Angular 组件,点击右键打开上下文菜单,然后转到 Refactor | Extract Component(重构 | 提取组件)。或者,可以按 ^T / Ctrl+Alt+Shift+T,从 Refactor This(重构此)弹出窗口中选择 Extract Component(提取组件)。



Vue 和 React 特性的类型检查


如果有什么地方不对劲,当然是越早知道越好,特别是类型属性不正确时。当绑定到 React 和 Vue 中的属性的表达式中使用了不正确的 TypeScript 类型时,IDE 会发出通知。



require 语句自动导入


每次都手动导入引用的库可能会干扰您手头的工作。此前,补全 ES6 模块中的符号时,WebStorm 已经会添加缺少的 import 语句(与其他 JetBrains IDE 一样)。现在,它们可以对 CommonJS 模块实现相同功能,在代码补全时插入require语句。



重做的 Deno 集成


JavaScript 和 TypeScript 的新运行时 Deno 于 2020 年发布。我们第一时间添加了支持,但是,去年我们迫不得已进行了重做。其中最大的变化是改为使用 Deno LSP 集成,而不是以自定义 Deno 插件扩展 TypeScript 服务。如果您正在使用 Deno,那试一试更新后的插件吧!您可以在这篇博文中详细了解支持的内容。


希望您喜欢今天的分享,并学到新知识。请告诉我们您的想法和感兴趣的内容!如果您想看到自己喜欢的功能,也请留言告诉我们。


本博文英文原作者:David Watson

⏬ 戳「阅读原文」了解更多

本文分享自微信公众号 - JetBrains(JetBrainsChina)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

20 个值得收藏的实用 JavaScript 技巧

20 个值得收藏的实用 JavaScript 技巧

1. 确定对象的数据类型

function myType(type) {
  return Object.prototype.toString.call(type).slice(8, -1);

使用 Object.prototype.toString,通过传入不同类型的判断返回不同的判断函数,一行代码,简洁优雅灵活;

2. 循环遍历数组 map 方法

const myMap = function (fn, context) {
  let arr = Array.prototype.slice.call(this);
  let resultArr = Array();
  for (let i = 0; i < arr.length; i++) {
    if (!arr.hasOwnProperty(i)) continue;
    resultArr[i] = fn.call(context, arr[i], i, this);
  }
  return resultArr;
};

Array.prototype.myMap = myMap;
let arr = [1, 2, 3];
console.log(arr.myMap((item) => item + 1)); // 2,3,4

值得注意的是,map 第二个参数在第一个参数回调中指向 this。如果第一个参数是箭头函数,则第二个 this 的设置无效。

3. 循环遍历数组过滤方法

const myFilter = function (fn, context) {
    let arr = Array.prototype.slice.call(this)
    let resultArr = []
    for (let i = 0; i < arr.length; i++) {
        if(!arr.hasOwnProperty(i)) continue;
         fn.call(context, arr[i], i, this) && resultArr.push(arr[i])
    }
    return resultArr
}
Array.prototype.myFilter = myFilter
let arr = [1, 2, 3]
console.log(arr.myFilter(item => item === 2)) // [2]

4. 使用 reduce 实现数组过滤方法

const myFilter2 = function (fn, context) {
    return this.reduce((total, current, index) => {
        return fn.call(context, current, index, this) ? [...total, current] : [...total]
    }, [])
}

5. 遍历数组的一些方法

const mySome = function (fn, context) {
  let arr = Array.prototype.slice.call(this);
  // The empty array returns false directly, and the every method of the array returns true conversely
  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.mySome = mySome;

let arr = [1, 2, 3];
console.log(arr.mySome((item) => item === 2));

执行 some 的数组如果是空数组总是返回 false,而另一个数组的 every 方法中的数组如果是空数组总是返回 true。

6. 通过循环实现数组的 reduce 方法

Array.prototype.myReduce = function (fn, initialValue) {
    let arr = Array.prototype.slice.call(this)
    let startItem
    let startIndex
    if (initialValue === undefined) {
        // Finds the element and subscript of the first non-empty (real) unit
        for (let i = 0; i < arr.length; i++) {
            if (!arr.hasOwnProperty(i)) continue
            startIndex = i
            startItem = arr[i]
            break
        }
    } else {
        startItem = initialValue
    }
    // The starting point for traversal is the real element after the real element found in the previous step
    // Each iteration skips the elements of the empty cell
    for (let i = ++startIndex || 0; i < arr.length; i++) {
        if (!arr.hasOwnProperty(i)) continue
        startItem = fn.call(null, startItem, arr[i], i, this)
    }
    return startItem
}

Array.prototype.myReduce = myReduce


let arr = [1, 2, 3]

console.log(arr.myReduce((acc, cur) => acc + cur)) // 6
console.log(arr.reduce((acc, cur) => acc + cur)) // 6

7. 使用 reduce 实现 array 的 flat 方法

// reduce implements array.prototype.flat, Array flat
const myFlat = function (depth = 1) {
    let arr = Array.prototype.slice.call(this)
    if (depth === 0) return arr
    return arr.reduce((total, current) => {
        if (Array.isArray(current)) {
            // You need to bind this with call, otherwise it points to the window
            return [...total, ...myFlat.call(current, depth-1)]
        } else {
            return [...total, current]
        }
    }, [])
}

Array.prototype.myFlat  = myFlat
let arr = [1, 2, [3, 4, [5, 6,[''a'',''b'',''c'',[''d'']], 7, 8], 9], 10, 11, 12, [13, 14]]

console.log (arr.myFlat ()) 因为 myFlat 依赖这个指向,所以需要在 reduce 遍历的时候指定 myFlat 的这个指向;否则默认指向 window,会报错。

当数组的元素还是数组时,使用 ES6 的扩展运算符对其进行降维(ES5 中可以使用 concat 方法)。但是数组元素内部可能有嵌套数组,所以需要递归调用 selfFlat。

同时,原生的 Flat 方法支持一个深度参数来表示降维的深度。默认值为 1,表示数组减少一维。

传递 Infinity 将传递的数组变成一维数组:

8. 实现 ES6 类语法

function Animal(name) {
    this.name = name
}

Animal.staticFunc = function () {
    console.log(''staticFunc'')
}
Animal.prototype.sleep = function () {
    console.log(''animal is sleeping'')
}

//Parasitic combinatorial inheritance + inheritance between constructors
function Dog(name, color) {
    Animal.call(this, name)
    this.color = color
}

function inherit(subType, superType) {
    //Due to the nature of JavaScript reference types and functions passing by value, you cannot change the reference address of subType
    subType.prototype = Object.create(superType.prototype, {
        constructor: {
            enumerable: false,
            configurable: true,
            writable: true,
            // Points to subclasses, consistent with the default inheritance behavior
            value: subType
        }
    })
    //The child constructor inherits the parent constructor (the child inherits the static methods and static properties of the parent class)
    Object.setPrototypeOf(subType, superType)
}

inherit(Dog, Animal)

//You need to add the prototype method to Dog after inheritance, otherwise it will be overwritten
Dog.prototype.barking = function () {
    console.log(''wang!'')
}


let brownTeddy = new Dog(''teddy'', ''brown'')
Dog.staticFunc()
console.log(brownTeddy)
brownTeddy.sleep()
brownTeddy.barking()

Create 方法创建一个空 Object,并从 Object.create 方法的参数中继承这个空 Object。然后让子类的原型(subType)等于空对象,就可以实现子类的原型等于空对象,空对象等于父类的继承原型。

Object.create 支持第二个参数,它为生成的空对象定义属性和属性 / 访问器描述符。我们可以给这个空对象一个更符合默认继承行为的构造函数属性。它也是一个不能枚举的内部属性(Enumerable: False)。

ES6 类允许子类从父类继承静态方法和静态属性,而普通的寄生组合继承只能在实例之间实现。对于类到类的继承,需要定义额外的方法。

这里我们使用 Object.setProtoTypeof 将 superType 设置为 subType 的原型,从而能够从父类继承静态方法和静态属性。

9. 函数的焦化

const display = (a, b, c, d, e, f) => [a, b, c, d, e, f];

/**
 * @description Currization of a function (How many times a currization function needs to be executed according to the number of parameters of the function before currization)
 * @param {function} fn -The Currified function
 */

function curry(fn) {
    if (fn.length <= 1) return fn;
    const generator = (...args) => {
        if (fn.length === args.length) {
            //Executes fn and returns the execution result
            return fn(...args)
        } else {
            return (...args2) => {
                //Return generator function
                return generator(...args, ...args2)
            }
        }
    }
    return generator
}

const curriedDisplay = curry(display);
console.log("curriedDisplay", curriedDisplay(1)(2)(3)(4)(5)(6));

Currization 是函数式编程中的一项重要技术,该技术将一个接受多个参数的函数转换为一系列接受一个参数的函数。

函数式编程 compose 另一个重要的功能,并且要能够进行函数组合,函数的组合只接受一个参数,所以如果你必须接受多个函数的需求并且需要使用 compose 函数组合,就需要使用 compose 的部分 curry 准备复合函数,让它总是只接受一个参数。

10. 函数修正(占位符支持)

const curry3 = (fn, placeholder = "_") => {
    curry3.placeholder = placeholder
    if (fn.length <= 1) return fn;
    let argsList = []
    const generator = (...args) => {
        let currentPlaceholderIndex = -1 
        args.forEach(arg => {
            let placeholderIndex = argsList.findIndex(item => item === curry3.placeholder)
            if (placeholderIndex < 0) {
                currentPlaceholderIndex = argsList.push(arg) - 1
               
                // (1,''_'')(''_'',2)
            } else if (placeholderIndex !== currentPlaceholderIndex) {
                argsList[placeholderIndex] = arg
            } else { 
                argsList.push(arg)
            }
        })
        let realArgsList = argsList.filter(arg => arg !== curry3.placeholder) 
        if (realArgsList.length >= fn.length) {
            return fn(...argsList)
        } else {
            return generator
        }
    }

    return generator
}

const curriedDisplay3 = curry3(display);
console.log("curriedDisplay3", curriedDisplay3(''_'', 2)(1, ''_'', 4)(3, ''_'',)(''_'', 5)(6)(7, 8))

如果当前轮参数包含占位符,则将其放置在内部保存数组的末尾。当前轮的元素不填充当前轮参数的占位符,而只填充之前传入的占位符。

11. 斐波那契数列及其优化

const speed = function (fn, num) {
    console.time(''time'')
    let value = fn(num)
    console.timeEnd(''time'')
    console.log(`result:${value}`)
}

/**
 * @description Fibonacci numbers
 * @param {number} n -Number of positions
 * @return {number} The argument corresponds to a number in a sequence
 **/
let fibonacci = function (n) {
    if (n < 1) throw new Error(''Parameter is wrong'')
    if (n === 1 || n === 2) return 1
    return fibonacci(n - 1) + fibonacci(n - 2)
}

speed(fibonacci, 40)


//Memory function
const memory = function (fn) {
    let obj = {}
    return function (n) {
        if (obj[n] === undefined) obj[n] = fn(n)
        return obj[n]
    }
}
fibonacci = memory(fibonacci)

speed(fibonacci, 40)


/**
 * @description Fibonacci dynamic programming version (Optimal)
 **/
function fibonacci_DP(n) {
    let res = 1
    if (n === 1 && n === 2) return res
    n = n - 2
    let cur = 1
    let pre = 1
    while (n) {
        res = cur + pre
        pre = cur
        cur = res
        n--
    }
    return res
}

speed(fibonacci_DP, 40)

使用函数内存,可以为经常依赖先前结果的计算节省大量时间,例如斐波那契数列。缺点是闭包中的 obj 对象占用了额外的内存。

另外,动态规划的空间复杂度比前者低,也是比较推荐的方案。

12. 实现绑定方法

const isComplexDataType = obj => (typeof obj === ''object'' || typeof obj === ''function'') && obj !== null

// Implement a simple bind
const myBind = function (bindTarget, ...args1) {
    if (typeof this !== ''function'') throw new TypeError(''Bind must be called on a function'')
    const originFunc = this
    const boundFunc = function (...args2) {
        // Calls using the new keyword return a new object
        if (new.target) {
            let res = originFunc.call(this, ...args1, ...args2)
            //If the constructor returns an object, that object is returned
            if (isComplexDataType(res)) return res
            //Otherwise, the newly created object is returned
            return this
        } else {
            return originFunc.call(bindTarget, ...args1, ...args2)
        }
    }
    if (originFunc.prototype) {
        boundFunc.prototype = originFunc.prototype
    }

    const desc = Object.getOwnPropertyDescriptors(originFunc)
    Object.defineProperties(boundFunc, {
        length: desc.length,
        name: Object.assign(desc.name, {
            value: `bound ${desc.name.value}`
        })
    })
    return boundFunc
}

实现函数的 bind 方法的核心使用调用绑定指向 this,同时考虑到其他情况如:

  • 当 bind 返回的函数作为构造函数被 new 调用时,绑定值失效,变为 new 指定的对象。
  • 定义绑定函数的 length 和 name 属性(不可枚举的属性)。
  • 绑定函数的 prototype 必须指向 prototype 原函数的 。

13. 实现调用方法

const myCall = function (context, ...args) {
    let func = this
    context || (context = window)
    if (typeof func !== ''function'') throw new TypeError(''this is not function'')
    let caller = Symbol(''caller'')
    context[caller] = func
    let res = context[caller](...args)
    delete context[caller]
    return res
}

原理是将函数作为 context 传入参数的属性执行。ES6 Symbol 类型用于防止属性冲突。

14. 简单的 CO 模块

//Self-executing generator functions

const data = "{a:1,b:2}";
const data2 = "{c:3,d:4}";
const data3 = "{e:5,f:6}";

const api = function (data) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(data);
    }, 1000);
  });
};

function* func() {
  let res = yield api(data);
  console.log(res);
  let res2 = yield api(data2);
  console.log(res2);
  let res3 = yield api(data3);
  console.log(res3);
  console.log(res, res2, res3);
}

function makePromisify(source) {
  if (source.then && typeof source.then === "function") return source;
  return Promise.resolve(source);
}

function run(generatorFunc) {
  let it = generatorFunc();
  let result = it.next();

  return new Promise((resolve, reject) => {
    const next = function (result) {
      if (result.done) {
        return resolve(result.value);
      }
      result.value = makePromisify(result.value);
      result.value
        .then((res) => {
          let result = it.next(res);
          //Recursively execute the next function
          next(result);
        })
        .catch((err) => {
          reject(err);
        });
    };
    next(result);
  });
}

run(func);

run 函数接受一个生成器函数,每次 run 函数包裹的生成器函数遇到 yield 关键字时停止,当 yield 后的 promise 成功解析时,自动调用 next 方法执行到下一个 yield 关键字。

最后,每次成功解析一个 promise,都会解析下一个 promise。

当所有的结果都解析成功后,所有解析的结果都会被打印出来,演变成今天最常用的 async/await 语法。

15. 功能防抖

/**
 * @description debounce
 * @param {Function} func -Functions that need function stabilization
 * @param {Number} time -Delay time
 * @param {Options} options -Configuration items
 * @return {Function} -A function that has been shaken out
 **/

/**
 * @typedef {Object} Options -Configuration items
 * @property {Boolean} leading -Whether an extra trigger is required to start
 * @property {Boolean} trailing -Whether an additional trigger is required after the end
 * @property {this} context -this
 **/

const debounce = (func, time = 20, 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
};

16. 函数节流

/**
 * @description throttle
 * @param {Function} func -Functions that require function throttling
 * @param {Number} time -Delay time
 * @param {Options} options -Configuration items
 * @return {Function} -经过节流处理的函数
 **/

/**
 * @typedef {Object} Options -Configuration items
 * @property {Boolean} leading -Whether an extra trigger is required to start
 * @property {Boolean} trailing -Whether an additional trigger is required after the end
 * @property {this} context -this
 **/

const throttle = (func, time = 17, options = {
    // leading 和 trailing 无法同时为 false
    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
};

添加尾随选项以指示是否在序列结束时触发附加事件。

17. 图片的延迟加载

// getBoundingClientRect lazy Load
let imgList1 = [...document.querySelectorAll(".get_bounding_rect")]
let num = imgList1.length

let 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 the image to the remove list after loading successfully
                deleteIndexList.push(index)
                count++
                if (count === num) {
                    //Unbind the Scroll event when all images are loaded
                    document.removeEventListener(''scroll'',lazyLoad1)
                }
            }
        })
        // Delete images that have been loaded
        imgList1 = imgList1.filter((_,index)=>!deleteIndexList.includes(index))

    }
})()

// The throttling function of throttle.js is referenced here
lazyLoad1 = proxy(lazyLoad1, 100)

document.addEventListener(''scroll'', lazyLoad1)
// Manually load the image once. Otherwise, the image on the first screen cannot be loaded without triggering scrolling
lazyLoad1()



// intersectionObserver lazy Load
let imgList2 = [...document.querySelectorAll(".intersection_observer")]

let lazyLoad2 = function () {
    // instantiation observer
    let observer = new IntersectionObserver(entries => {
        entries.forEach(entry => {
            if (entry.intersectionRatio > 0) {
                entry.target.src = entry.target.dataset.src
                observer.unobserve(entry.target)
            }
        })
    })
    imgList2.forEach(img => {
        observer.observe(img)
    })
}

lazyLoad2()

getBoundClientRect 的实现监听滚动事件(建议为监听事件添加节流)。图片加载完成后,会从 img 标签组成的 DOM 列表中删除。最后,加载监听器事件后,所有图像都需要解除绑定。

IntersectionObserver 是通过实例化一个 intersectionObserver 并使其观察所有 IMG 标签来实现的。

当 img 标签进入查看区域时,实例化时执行回调。同时传入一个回调,保存实例来观察所有元素的某种状态,比如每个元素的边界,当前元素对应的 DOM 节点,当前元素进入查看区域的比例。每当一个元素进入查看区域时,将真实图像分配给当前 IMG 标签,同时不观察它。

18. 新关键字

const isComplexDataType = obj => (typeof obj === ''object'' || typeof obj === ''function'') && obj !== null

const myNew = function (fn, ...rest) {
    let instance = Object.create(fn.prototype)
    let res = fn.call(instance, ...rest)
    return isComplexDataType(res) ? res : instance
}

function Person(name, sex) {
    this.name = name
    this.sex = sex
}


let newPerson = new Person(''tony'', ''woman'')
let myNewPerson = myNew(Person, ''tony1'', ''man'')

console.log(newPerson)
console.log(myNewPerson)

19. 实现对象分配

"use strict" 

const isComplexDataType = obj => (typeof obj === ''object'' || typeof obj === ''function'') && obj !== null


const myAssign = function (target, ...source) {
    if (target == null) throw new TypeError(''Cannot convert undefined or null to object'')
    return source.reduce((acc, cur) => {
        isComplexDataType(acc) || (acc = new Object(acc)); 
        if (cur == null) return acc; 
        [...Object.keys(cur), ...Object.getOwnPropertySymbols(cur)].forEach(key => {
            acc[key] = cur[key]
        })
        return acc
    }, target)
}

Object.myAssign = myAssign


let target = {
    a: 1,
    b: 1
}

let obj1 = {
    a: 2,
    b: 2,
    c: undefined
}

let obj2 = {
    a: 3,
    b: 3,
    [Symbol("a")]: 3,
    d: null
}

console.log(Object.myAssign(target, obj1, obj2))
console.log(Object.myAssign("abd", null, undefined))

20. 实例化

const myInstanceof = function (left, right) {
    let proto = Object.getPrototypeOf(left)
    while (true) {
        if (proto == null) return false
        if (proto === right.prototype) {
            return true
        }
        proto = Object.getPrototypeOf(proto)
    }
}

console.log(myInstanceof({}, Array))

结论

到这里,我们我们终于得到它了。20 个出色的技巧,可帮助您编写更好、更高效的代码。阅读前你知道多少?

最后推荐一套好不错的 JavaScript 从入门到精通全套完整版教程,有需要的小伙伴建议收藏学习!

2020最新JavaScript开发必须知道的41个技巧,你会几个?

2020最新JavaScript开发必须知道的41个技巧,你会几个?

前言

JS是前端的核心,但有些使用技巧你还不一定知道;
本文梳理了JS的41个技巧,帮助大家提高JS的使用技巧;
文章有点长,可以clone下源码,直接撸,源码地址请戳全部源码,原创不易,欢迎star;
序列文章:
Vue 开发必须知道的 36 个技巧
React 开发必须知道的 34 个技巧




Array

1.数组交集

普通数组

const arr1 = [1, 2, 3, 4, 5 , 8 ,9],arr2 = [5, 6, 7, 8, 9];

const intersection = arr1.filter(function (val) { return arr2.indexOf(val) > -1 })
console.log(intersection) //[5, 8, 9]
复制代码

数组对象
数组对象目前仅针对value值为简单的Number,String,Boolan数据类型

const arr1 = [{ name: ''name1'', id: 1 }, { name: ''name2'', id: 2 }, { name: ''name3'', id: 3 }, { name: ''name5'', id: 5 }];
const arr2 = [{ name: ''name1'', id: 1 }, { name: ''name2'', id: 2 }, { name: ''name3'', id: 3 }, { name: ''name4'', id: 4 }, { name: ''name5'', id: 5 }]; const result = arr2.filter(function (v) { return arr1.some(n => JSON.stringify(n) === JSON.stringify(v)) }) console.log(result); // [{ name: ''name1'', id: 1 },{ name: ''name2'', id: 2 },{ name: ''name3'', id: 3 },{ name: ''name5'', id: 5 }] 复制代码

2.数组并集

普通数组

const arr1 = [1, 2, 3, 4, 5, 8, 9]
const arr2 = [5, 6, 7, 8, 9];
const result = arr1.concat(arr2.filter(v => !arr1.includes(v)))
console.log(result) //[1, 2, 3, 4,5, 8, 9]
复制代码

数组对象

const arr1 = [{ name: ''name1'', id: 1 }, { name: ''name2'', id: 2 }, { name: ''name3'', id: 3 }];
const arr2 = [{ name: ''name1'', id: 1 }, { name: ''name4'', id: 4 }, { name: ''name5'', id: 5 }]; let arr3 = arr1.concat(arr2); let result = []; let obj = []; result = arr3.reduce(function (prev, cur, index, arr) { obj[cur.id] ? '''' : obj[cur.id] = true && prev.push(cur); return prev; }, []); console.log(result); //[{ name: ''name1'', id: 1 },{ name: ''name2'', id: 2 },{ name: ''name3'', id: 3 },{ name: ''name4'', id: 4 },{ name: ''name5'', id: 5 }]

另外要注意:技术是不断更新的。要跟上步伐,在此赠送2020最新企业级别Vue3.0/Js/ES6/TS/React/node等实战视频教程,想学的可进裙 519293536 免费获取,小白勿进哦!

 

3.数组差集

数组arr1相对于arr2所没有的
普通数组

const arr1 = [1, 2, 3, 4, 5, 8, 9]
const arr2 = [5, 6, 7, 8, 9];
const diff = arr1.filter(item => !new Set(arr2).has(item))
console.log(diff) //[ 1, 2, 3, 4 ]
复制代码

数组对象

// 对象数组
let arr1 = [{ name: ''name1'', id: 1 }, { name: ''name2'', id: 2 }, { name: ''name3'', id: 3 }];
let arr2 = [{ name: ''name1'', id: 1 }, { name: ''name4'', id: 4 }, { name: ''name5'', id: 5 }]; let result = arr1.filter(function (v) { return arr2.every(n => JSON.stringify(n) !== JSON.stringify(v)) }) console.log(result); // [ { name: ''name2'', id: 2 }, { name: ''name3'', id: 3 } ] 复制代码

4.数组补集

两个数组各自没有的集合
普通数组

const arr1 = [1, 2, 3, 4, 5, 8, 9]
const arr2 = [5, 6, 7, 8, 9];
const difference = Array.from(new Set(arr1.concat(arr2).filter(v => !new Set(arr1).has(v) || !new Set(arr2).has(v)))) 
console.log(difference) //[ 1, 2, 3, 4, 6, 7 ]
复制代码

数组对象

let arr1 = [{ name: ''name1'', id: 1 }, { name: ''name2'', id: 2 }, { name: ''name3'', id: 3 }];
let arr2 = [{ name: ''name1'', id: 1 }, { name: ''name4'', id: 4 }, { name: ''name5'', id: 5 }]; let arr3 = arr1.concat(arr2); let result = arr3.filter(function (v) { return arr1.every(n => JSON.stringify(n) !== JSON.stringify(v)) || arr2.every(n => JSON.stringify(n) !== JSON.stringify(v)) }) console.log(result); // [{ name: ''name2'', id: 2 },{ name: ''name3'', id: 3 },{ name: ''name4'', id: 4 },{ name: ''name5'', id: 5 }] 复制代码

总结一下,差集就是数组arr1相对于arr2所没有的集合,补集是两个数组各自没有的集合

5.数组去重

普通数组

console.log(Array.from(new Set([1, 2, 3, 3, 4, 4]))) //[1,2,3,4]
console.log([...new Set([1, 2, 3, 3, 4, 4])]) //[1,2,3,4]
复制代码

数组对象

const arr = [{ name: ''name1'', id: 1 }, { name: ''name2'', id: 2 }, { name: ''name3'', id: 3 }, { name: ''name1'', id: 1 }, { name: ''name4'', id: 4 }, { name: ''name5'', id: 5 }]; const obj = []; const result = arr.reduce(function (prev, cur, index, arr) { obj[cur.id] ? '''' : obj[cur.id] = true && prev.push(cur); return prev; }, []); console.log(result) //[{ name: ''name1'', id: 1 },{ name: ''name2'', id: 2 },{ name: ''name3'', id: 3 },{ name: ''name4'', id: 4 },{ name: ''name5'', id: 5 }] 复制代码

6.数组排序

普通数组

console.log([1, 2, 3, 4].sort((a, b) => a - b)); // [1, 2,3,4] 升序
console.log([1, 2, 3, 4].sort((a, b) => b - a)); // [4,3,2,1] 降序
复制代码

数组对象

const arr1 = [{ name: "Rom", age: 12 }, { name: "Bob", age: 22 }].sort((a, b) => { return a.age - b.age })//升序
const arr2 = [{ name: "Rom", age: 12 }, { name: "Bob", age: 22 }].sort((a, b) => { return -a.age + b.age })//降序 console.log(arr2) // [{ name: ''Bob'', age:22 }, { name: ''Rom'', age: 12 }] console.log(arr1) // [ { name: ''Rom'', age: 12 }, { name: ''Bob'', age: 22 } ] 复制代码

两个种类型数组都可以使用sort排序,sort是浏览器内置方法;
默认是升序排序,默认返回一个函数,有两个参数:
(a, b) => a - b 是升序;
(a, b) => b - a 是降序。


7.最大值

普通数组

Math.max(...[1, 2, 3, 4]) //4
Math.max.apply(this, [1, 2, 3, 4]) //4
[1, 2, 3, 4].reduce((prev, cur, curIndex, arr) => {
   return Math.max(prev, cur);
}, 0) //4
复制代码

取数组对象中id的最大值

const arr = [{ id: 1, name: ''jack'' },{ id: 2, name: ''may'' },{ id: 3, name: ''shawn'' },{ id: 4, name: ''tony'' }]
const arr1 = Math.max.apply(Math, arr.map(item => { return item.id })) const arr2 = arr.sort((a, b) => { return b.id - a.id })[0].id console.log(arr1) // 4 console.log(arr2) // 4 复制代码

8.数组求和

普通数组

[1, 2, 3, 4].reduce(function (prev, cur) {
  return prev + cur;
}, 0) //10 
复制代码

数组对象

const sum = [{age:1},{age:2}].reduce(function (prev, cur) {
  return prev + cur.age;
}, 0) //3
console.log(sum)
复制代码

9.数组合并

普通数组

const arr1 =[1, 2, 3, 4].concat([5, 6]) //[1,2,3,4,5,6]
const arr2 =[...[1, 2, 3, 4],...[4, 5]] //[1,2,3,4,5,6]
const arrA = [1, 2], arrB = [3, 4]
const arr3 =Array.prototype.push.apply(arrA, arrB)//arrA值为[1,2,3,4]
复制代码

数组对象

const arr4 = [{ age: 1 }].concat([{ age: 2 }])
const arr5 = [...[{ age: 1 }],...[{ age: 2 }]]
console.log(arr4) //[ { age: 1 }, { age: 2 } ]
console.log(arr5) // [ { age: 1 }, { age: 2 } ]
复制代码

10.数组是否包含值

普通数组

console.log([1, 2, 3].includes(4)) //false
console.log([1, 2, 3].indexOf(4)) //-1 如果存在换回索引
console.log([1, 2, 3].find((item) => item === 3)) //3 如果数组中无值返回undefined
console.log([1, 2, 3].findIndex((item) => item === 3)) //2 如果数组中无值返回-1
复制代码

数组对象

const flag = [{age:1},{age:2}].some(v=>JSON.stringify(v)===JSON.stringify({age:2}))
console.log(flag)
复制代码

11.数组每一项都满足

普通数组

[1, 2, 3].every(item => { return item > 2 })
复制代码

数组对象

const arr = [{ age: 3 }, { age: 4 }, { age: 5 }]
arr.every(item => { return item.age > 2 }) // true
复制代码

12.数组有一项满足

普通数组

[1, 2, 3].some(item => { return item > 2 })
复制代码

数组对象

const arr = [{ age: 3 }, { age: 4 }, { age: 5 }]
arr.some(item => { return item.age < 4 }) // true
复制代码

13.版本号排序

方法一

function sortNumber(a, b) {
  return a - b
}
const b = [1,2,3,7,5,6]
const a = ["1.5", "1.5", "1.40", "1.25", "1.1000", "1.1"]; console.log(a.sort(sortNumber)); // [ 1, 2, 3, 5, 6, 7 ] console.log(b.sort(sortNumber)); //[ ''1.1000'', ''1.1'', ''1.25'', ''1.40'', ''1.5'', ''1.5'' ] 复制代码

可见sort排序对整数可以,类似版本号这个格式就不适用了,因为sort函数在比较字符串的时候,是比较字符串的Unicode进行排序的。

方法二

//假定字符串的每节数都在5位以下
//去除数组空值||空格
if (!Array.prototype.trim) {
  Array.prototype.trim = function () {
    let arr = []; this.forEach(function (e) { if (e.match(/\S+/)) arr.push(e); }) return arr; } } //提取数字部分 function toNum(a) { let d = a.toString(); let c = d.split(/\D/).trim(); let num_place = ["", "0", "00", "000", "0000"], r = num_place.reverse(); for (let i = 0; i < c.length; i++) { let len = c[i].length; c[i] = r[len] + c[i]; } let res = c.join(''''); return res; } //提取字符 function toChar(a) { let d = a.toString(); let c = d.split(/\.|\d/).join(''''); return c; } function sortVersions(a, b) { let _a1 = toNum(a), _b1 = toNum(b); if (_a1 !== _b1) return _a1 - _b1; else { _a2 = toChar(a).charCodeAt(0).toString(16); _b2 = toChar(b).charCodeAt(0).toString(16); return _a2 - _b2; } } let arr1 = ["10", "5", "40", "25", "1000", "1"]; let arr2 = ["1.10", "1.5", "1.40", "1.25", "1.1000", "1.1"]; let arr3 = ["1.10c", "1.10b", "1.10C", "1.25", "1.1000", "1.10A"]; console.log(arr1.sort(sortVersions)) //[ ''1'', ''5'', ''10'', ''25'', ''40'', ''1000'' ] console.log(arr2.sort(sortVersions)) //[ ''1.1'', ''1.5'', ''1.10'', ''1.25'', ''1.40'', ''1.1000'' ] console.log(arr3.sort(sortVersions)) // [ ''1.10A'', ''1.10C'', ''1.10b'', ''1.10c'', ''1.25'', ''1.1000'' ] 复制代码

可以看出这个函数均兼容整数,非整数,字母;
字母排序是根据Unicode排序的,所以1.10b在1.10C的后面

14. 对象转数组

将数组的key和value转化成数组

Object.keys({ name: ''张三'', age: 14 }) //[''name'',''age'']
Object.values({ name: ''张三'', age: 14 }) //[''张三'',14] Object.entries({ name: ''张三'', age: 14 }) //[[name,''张三''],[age,14]] Object.fromEntries([name, ''张三''], [age, 14]) //ES10的api,Chrome不支持 , firebox输出{name:''张三'',age:14} 复制代码

15.数组转对象

将数组的值转化为对象的value

const arrName = [''张三'', ''李四'', ''王五'']
const arrAge=[''20'',''30'',''40''] const arrDec = [''描述1'', ''描述2'', ''描述3''] const obj = arrName.map((item,index)=>{ return { name: item, age: arrAge[index],dec:arrDec[index]} }) console.log(obj) // [{ name: ''张三'', age: ''20'', dec: ''描述1'' },{ name: ''李四'', age: ''30'', dec: ''描述2'' },{ name: ''王五'', age: ''40'', dec: ''描述3'' }] 复制代码

16.数组解构

const arr=[1,2]; //后面一定要加分号,因为不加解释器会认为在读数组
[arr[1], arr[0]] = [arr[0], arr[1]]; // [2,1]
复制代码

Object

17.对象变量属性

const flag = true;
const obj = {
    a: 0,
    [flag ? "c" : "d"]: 2
};
// obj => { a: 0, c: 2 }
复制代码

18.对象多余属性删除

const { name, age, ...obj } = { name: ''张三'', age: 13, dec: ''描述1'', info: ''信息'' }
console.log(name)  // 张三
console.log(age)  // 13
console.log(obj)  // {dec: ''描述1'', info: ''信息'' } 复制代码

19.对象嵌套属性解构

const { info:{ dec} } = { name: ''张三'', age: 13, info:{dec: ''描述1'', info: ''信息'' }}
console.log(dec) // 描述1
复制代码

20.解构对象属性别名

const { name:newName } = { name: ''张三'', age: 13 }
console.log(newName)  // 张三
复制代码

21.解构对象属性默认值

const { dec=''这是默认dec值'' } = { name: ''张三'', age: 13 }
console.log(dec) //这是默认dec值
复制代码

22.拦截对象

利用Object.defineProperty拦截对象
无法拦截数组的值

let obj = { name: '''', age: '''', sex: '''' },
  defaultName = ["这是姓名默认值1", "这是年龄默认值1", "这是性别默认值1"]; Object.keys(obj).forEach(key => { Object.defineProperty(obj, key, { // 拦截整个object 对象,并通过get获取值,set设置值,vue 2.x的核心就是这个来监听 get() { return defaultName; }, set(value) { defaultName = value; } }); }); console.log(obj.name); // [ ''这是姓名默认值1'', ''这是年龄默认值1'', ''这是性别默认值1'' ] console.log(obj.age); // [ ''这是姓名默认值1'', ''这是年龄默认值1'', ''这是性别默认值1'' ] console.log(obj.sex); // [ ''这是姓名默认值1'', ''这是年龄默认值1'', ''这是性别默认值1'' ] obj.name = "这是改变值1"; console.log(obj.name); // 这是改变值1 console.log(obj.age); // 这是改变值1 console.log(obj.sex); // 这是改变值1 let objOne = {}, defaultNameOne = "这是默认值2"; Object.defineProperty(obj, ''name'', { get() { return defaultNameOne; }, set(value) { defaultNameOne = value; } }); console.log(objOne.name); // undefined objOne.name = "这是改变值2"; console.log(objOne.name); // 这是改变值2 复制代码

利用proxy拦截对象

let obj = { name: '''', age: '''', sex: '''' }
let handler = { get(target, key, receiver) { console.log("get", key); return Reflect.get(target, key, receiver); }, set(target, key, value, receiver) { console.log("set", key, value); // set name 李四 // set age 24 return Reflect.set(target, key, value, receiver); } }; let proxy = new Proxy(obj, handler); proxy.name = "李四"; proxy.age = 24; 复制代码

defineProterty和proxy的对比:
1.defineProterty是es5的标准,proxy是es6的标准;
2.proxy可以监听到数组索引赋值,改变数组长度的变化;
3.proxy是监听对象,不用深层遍历,defineProterty是监听属性;
4.利用defineProterty实现双向数据绑定(vue2.x采用的核心)



23.对象深度拷贝

JSON.stringify深度克隆对象;
1.无法对函数 、RegExp等特殊对象的克隆;
2.会抛弃对象的constructor,所有的构造函数会指向Object;
3.对象有循环引用,会报错


const objDeepClone = obj => {
  return clone(obj)
}

const isType = (obj, type) => {
  if (typeof obj !== ''object'') return false; // 判断数据类型的经典方法: const typeString = Object.prototype.toString.call(obj); let flag; switch (type) { case ''Array'': flag = typeString === ''[object Array]''; break; case ''Date'': flag = typeString === ''[object Date]''; break; case ''RegExp'': flag = typeString === ''[object RegExp]''; break; default: flag = false; } return flag; }; /** * deep clone * @param {[type]} parent object 需要进行克隆的对象 * @return {[type]} 深克隆后的对象 */ const clone = parent => { // 维护两个储存循环引用的数组 const parents = [] const children = [] const _clone = parent => { if (parent === null) return null if (typeof parent !== ''object'') return parent let child, proto if (isType(parent, ''Array'')) { // 对数组做特殊处理 child = [] } else if (isType(parent, ''RegExp'')) { // 对正则对象做特殊处理 child = new RegExp(parent.source, getRegExp(parent)) if (parent.lastIndex) child.lastIndex = parent.lastIndex } else if (isType(parent, ''Date'')) { // 对Date对象做特殊处理 child = new Date(parent.getTime()) } else { // 处理对象原型 proto = Object.getPrototypeOf(parent) // 利用Object.create切断原型链 child = Object.create(proto) } // 处理循环引用 const index = parents.indexOf(parent) if (index !== -1) { // 如果父数组存在本对象,说明之前已经被引用过,直接返回此对象 return children[index] } parents.push(parent) children.push(child) for (const i in parent) { // 递归 child[i] = _clone(parent[i]) } return child } return _clone(parent) } console.log(objDeepClone({ name: ''张三'', age: 23, obj: { name: ''李四'', age: 46}, arr:[1,2,3] })) // { name: ''张三'', age: 23, obj: { name: ''李四'', age: 46 }, arr: [ 1, 2, 3 ] } 复制代码

对象深度克隆实际上就是要兼容Array,RegExp,Date,Function类型;
克隆函数可以用正则取出函数体和参数,再定义一个函数将取出来的值赋值进去
详细请戳对象深度拷贝

24.对象是否相等

如果用JSON.stringify转化属性顺序不同,也不相等;
而且不支持无法对函数 、RegExp等特殊对象的克隆


function deepCompare(x, y) {
  var i, l, leftChain, rightChain;

  function compare2Objects(x, y) {
    var p;

    // remember that NaN === NaN returns false
    // and isNaN(undefined) returns true
    if (isNaN(x) && isNaN(y) && typeof x === ''number'' && typeof y === ''number'') { return true; } // Compare primitives and functions. // Check if both arguments link to the same object. // Especially useful on the step where we compare prototypes if (x === y) { return true; } // Works in case when functions are created in constructor. // Comparing dates is a common scenario. Another built-ins? // We can even handle functions passed across iframes if ((typeof x === ''function'' && typeof y === ''function'') || (x instanceof Date && y instanceof Date) || (x instanceof RegExp && y instanceof RegExp) || (x instanceof String && y instanceof String) || (x instanceof Number && y instanceof Number)) { return x.toString() === y.toString(); } // At last checking prototypes as good as we can if (!(x instanceof Object && y instanceof Object)) { return false; } if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) { return false; } if (x.constructor !== y.constructor) { return false; } if (x.prototype !== y.prototype) { return false; } // Check for infinitive linking loops if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) { return false; } // Quick checking of one object being a subset of another. // todo: cache the structure of arguments[0] for performance for (p in y) { if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { return false; } else if (typeof y[p] !== typeof x[p]) { return false; } } for (p in x) { if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) { return false; } else if (typeof y[p] !== typeof x[p]) { return false; } switch (typeof (x[p])) { case ''object'': case ''function'': leftChain.push(x); rightChain.push(y); if (!compare2Objects(x[p], y[p])) { return false; } leftChain.pop(); rightChain.pop(); break; default: if (x[p] !== y[p]) { return false; } break; } } return true; } if (arguments.length < 1) { return true; } for (i = 1, l = arguments.length; i < l; i++) { leftChain = []; //Todo: this can be cached rightChain = []; if (!compare2Objects(arguments[0], arguments[i])) { return false; } } return true; } const obj1 = { name: ''张三'', age: 23, obj: { name: ''李四'', age: 46 }, arr: [1, 2, 3], date:new Date(23), reg: new RegExp(''abc''), fun: ()=>{} } const obj2 = { name: ''张三'', age: 23, obj: { name: ''李四'', age: 46 }, arr: [1, 2, 3], date: new Date(23), reg: new RegExp(''abc''), fun: ()=>{} } console.log(deepCompare(obj1,obj2)) // true 复制代码

判断对象是否相等,实际上就是要处理Array,Date,RegExp,Object,Function的特殊类型是否相等

25.对象转化为字符串

通过字符串+Object 的方式来转化对象为字符串(实际上是调用 .toString() 方法)

''the Math object:'' + Math.ceil(3.4)                // "the Math object:4"
''the JSON object:'' + {name:''曹操''}              // "the JSON object:[object Object]" 复制代码

覆盖对象的toString和valueOf方法来自定义对象的类型转换

2  * { valueOf: ()=>''4'' }                // 8
''J'' + { toString: ()=>''ava'' }                // "Java"
复制代码

当+用在连接字符串时,当一个对象既有toString方法又有valueOf方法时候,JS通过盲目使用valueOf方法来解决这种含糊;
对象通过valueOf方法强制转换为数字,通过toString方法强制转换为字符串

'''' + {toString:()=>''S'',valueOf:()=>''J''}  //J
复制代码

Function

26.函数隐式返回值

(()=>3)()  //3
(()=>(
   3
))()
复制代码

函数省略大括号,或者将大括号改成小括号可以确保代码以单个语句的形式进行求值

27.函数自执行

const Func = function() {}(); // 常用

(function() {})(); // 常用
(function() {}()); // 常用 [function() {}()]; new function() {}; new function() {}(); void function() {}(); typeof function() {}(); delete function() {}(); + function() {}(); - function() {}(); ~ function() {}(); ! function() {}(); 复制代码

28.函数异步执行

Promise

Promise.reject(''这是第二个 reject 值'').then((data)=>{
  console.log(data)
}).catch(data=>{
  console.log(data) //这是第二个 reject 值
})
复制代码

Generator

function* gen(x) {
  const y = yield x + 6;
  return y;
}

// yield 如果用在另外一个表达式中,要放在()里面
// 像上面如果是在=右边就不用加()
function* genOne(x) {
  const y = `这是第一个 yield 执行:${yield x + 1}`;
  return y; } const g = gen(1); //执行 Generator 会返回一个Object,而不是像普通函数返回return 后面的值 g.next() // { value: 7, done: false } //调用指针的 next 方法,会从函数的头部或上一次停下来的地方开始执行,直到遇到下一个 yield 表达式或return语句暂停,也就是执行yield 这一行 // 执行完成会返回一个 Object, // value 就是执行 yield 后面的值,done 表示函数是否执行完毕 g.next() // { value: undefined, done: true } // 因为最后一行 return y 被执行完成,所以done 为 true 复制代码

Async/Await

function getSomething() {
    return "something"; } async function testAsync() { return Promise.resolve("hello async"); } async function test() { const v1 = await getSomething(); const v2 = await testAsync(); console.log(v1, v2); //something 和 hello async } test(); 复制代码

String

29.字符串翻转

function reverseStr(str = "") {
  return str.split("").reduceRight((t, v) => t + v);
}

const str = "reduce123"; console.log(reverseStr(str)); // "123recuder" 复制代码

30.url参数序列化

将对象序列化成url参数传递

function stringifyUrl(search = {}) {
  return Object.entries(search).reduce(
    (t, v) => `${t}${v[0]}=${encodeURIComponent(v[1])}&`, Object.keys(search).length ? "?" : "" ).replace(/&$/, ""); } console.log(stringifyUrl({ age: 27, name: "YZW" })); // "?age=27&name=YZW" 复制代码

31.url参数反序列化

一般会通过location.search拿到路由传递的参数,并进行反序列化得到对象

function parseUrlSearch() {
  const search = ''?age=25&name=TYJ''
  return search.replace(/(^\?)|(&$)/g, "").split("&").reduce((t, v) => { const [key, val] = v.split("="); t[key] = decodeURIComponent(val); return t; }, {}); } console.log(parseUrlSearch()); // { age: "25", name: "TYJ" } 复制代码

32.转化为字符串

const val = 1 + ""; // 通过+ ''''空字符串转化
console.log(val); // "1"
console.log(typeof val); // "string"

const val1 = String(1);
console.log(val1); // "1" console.log(typeof val1); // "string" 复制代码

Number

33.数字千分位

function thousandNum(num = 0) {
  const str = (+num).toString().split(".");
  const int = nums => nums.split("").reverse().reduceRight((t, v, i) => t + (i % 3 ? v : `${v},`), "").replace(/^,|,$/g, ""); const dec = nums => nums.split("").reduce((t, v, i) => t + ((i + 1) % 3 ? v : `${v},`), "").replace(/^,|,$/g, ""); return str.length > 1 ? `${int(str[0])}.${dec(str[1])}` : int(str[0]); } thousandNum(1234); // "1,234" thousandNum(1234.00); // "1,234" thousandNum(0.1234); // "0.123,4" console.log(thousandNum(1234.5678)); // "1,234.567,8" 复制代码

34.字符串转数字

方法一
用*1来转化为数字,实际上是调用.valueOf方法

''32'' * 1            // 32
''ds'' * 1            // NaN
null * 1            // 0
undefined * 1    // NaN
1  * { valueOf: ()=>''3'' }        // 3
复制代码

方法二

+ ''123''            // 123
+ ''ds''               // NaN
+ ''''                    // 0
+ null              // 0
+ undefined    // NaN
+ { valueOf: ()=>''3'' }    // 3
复制代码

35.判断小数是否相等

肯定有人会说这还不简单,直接用''===''比较;
实际上0.1+0.2 !==0.3,因为计算机不能精确表示0.1, 0.2这样的浮点数,所以相加就不是0.3了

Number.EPSILON=(function(){   //解决兼容性问题
    return Number.EPSILON?Number.EPSILON:Math.pow(2,-52);
})();
//上面是一个自调用函数,当JS文件刚加载到内存中,就会去判断并返回一个结果
function numbersequal(a,b){ 
    return Math.abs(a-b)<Number.EPSILON; } //接下来再判断 const a=0.1+0.2, b=0.3; console.log(numbersequal(a,b)); //这里就为true了 复制代码

36.双位运算符

双位运算符比Math.floor(),Math.ceil()速度快

~~7.5                // 7
Math.ceil(7.5)       // 8
Math.floor(7.5)      // 7


~~-7.5        		// -7
Math.floor(-7.5)     // -8
Math.ceil(-7.5)      // -7
复制代码

所以负数时,双位运算符和Math.ceil结果一致,正数时和Math.floor结果一致

37.取整和奇偶性判断

取整

3.3 | 0         // 3
-3.9 | 0        // -3

parseInt(3.3)  // 3
parseInt(-3.3) // -3

// 四舍五入取整
Math.round(3.3) // 3
Math.round(-3.3) // -3

// 向上取整
Math.ceil(3.3) // 4
Math.ceil(-3.3) // -3

// 向下取整
Math.floor(3.3) // 3
Math.floor(-3.3) // -4
复制代码

判断奇偶数

const num=5;
!!(num & 1) // true
!!(num % 2) // true
复制代码

Boolean

38.判断数据类型

function dataTypeJudge(val, type) {
  const dataType = Object.prototype.toString.call(val).replace(/\[object (\w+)\]/, "$1").toLowerCase();
  return type ? dataType === type : dataType; } console.log(dataTypeJudge("young")); // "string" console.log(dataTypeJudge(20190214)); // "number" console.log(dataTypeJudge(true)); // "boolean" console.log(dataTypeJudge([], "array")); // true console.log(dataTypeJudge({}, "array")); // false 复制代码

可判断类型:undefined、null、string、number、boolean、array、object、symbol、date、regexp、function、asyncfunction、arguments、set、map、weakset、weakmap

39.使用Boolean过滤数组假值

const compact = arr => arr.filter(Boolean)
compact([0, 1, false, 2, '''', 3, ''a'', ''e'' * 23, NaN, ''s'', 34]) //[ 1, 2, 3, ''a'', ''s'', 34 ] 复制代码

40.短路运算

||(或)

const flag = false || true //true
// 某个值为假时可以给默认值
const arr = false || []
复制代码

&&(与)

const flag1 = false && true //false
const flag2 = true && true //true 复制代码

41.switch 简写

可以用对象替代switch,提高代码可读性

switch(a) {
  case ''张三'':
    return ''age是12''
  case ''李四'': return ''age是120'' } // 使用对象替换后 const obj ={ ''张三'': ''age12'', ''李四'': ''age120'', } console.log(obj[''张三'']) 复制代码

结语:技术是不断更新的。要跟上步伐,在此赠送2020最新企业级别Vue3.0/Js/ES6/TS/React/node等实战视频教程,想学的可进裙 519293536 免费获取,小白勿进哦!

本文的文字及图片来源于网络加上自己的想法,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理

21个值得收藏的Javascript技巧

21个值得收藏的Javascript技巧

在本文中列出了21个值得收藏的Javascript技巧,在实际工作中,如果能适当运用,则大大提高工作效率。

  1 Javascript数组转换为CSV格式

  首先考虑如下的应用场景,有一个Javscript的字符型(或者数值型)数组,现在需要转换为以逗号分割的CSV格式文件。则我们可以使用如下的小技巧,代码如下:

var fruits = [''apple'', ''peaches'', ''oranges'', ''mangoes''];  
var str = fruits.valueOf();

  输出:apple,peaches,oranges,mangoes

  其中,valueOf()方法会将Javascript数组转变为逗号隔开的字符串。要注意的是,如果想不使用逗号分割,比如用|号分割,则请使用join方法,如下:

var fruits = [''apple'', ''peaches'', ''oranges'', ''mangoes''];
var str = fruits.join("|");

  输出: apple|peaches|oranges|mangoes

  2 将CSV格式重新转换回Javscript数组

  那么如何将一个CSV格式的字符串转变回Javascript数组呢?可以使用split()方法,就可以使用任何指定的字符去分隔,代码如下:

var str = "apple, peaches, oranges, mangoes";  
var fruitsArray = str.split(",");

  输出 fruitsArray[0]: apple

  3 根据索引移除数组中的某个元素

  假如需要从Javascript数组中移除某个元素,可以使用splice方法,该方法将根据传入参数n,移除数组中移除第n个元素(Javascript数组中从第0位开始计算)。

function removeByIndex(arr, index) {
     arr.splice(index, 1); 
} 
test = new Array(); 
test[0] = ''Apple''; 
test[1] = ''Ball''; test[2] = ''Cat''; test[3] = ''Dog''; 
alert("Array before removing elements: "+test); 
removeByIndex(test, 2); 
alert("Array after removing elements: "+test);

  则最后输出的为Apple,Ball,Dog

  4 根据元素的值移除数组元素中的值

  下面这个技巧是很实用的,是根据给定的值去删除数组中的元素,代码如下:

function removeByValue(arr, val) { 
    for(var i=0; i<arr.length; p="" }="" {="" ?thur?<="" somearray="["mon"," var="">

  当然,更好的方式是使用prototype的方法去实现,如下代码:

Array.prototype.removeByValue = function(val) { 
    for(var i=0; i<this.length; p="" }="" {="" ?wed?,="" somearray="["mon"," ?thur?]="" ?tue?,="" var="" break;="" 1);="" val)="" i++)="" somearray.removebyvalue(?tue?);<="" ..="">

  5 通过字符串指定的方式动态调用某个方法

  有的时候,需要在运行时,动态调用某个已经存在的方法,并为其传入参数。这个如何实现呢?下面的代码可以:

var strFun = "someFunction"; //someFunction 为已经定义的方法名 var strParam = "this is the parameter"; //要传入方法的参数 var fn = window[strFun]; //调用方法传入参数 fn(strParam);

  6 产生1到N的随机数

var random = Math.floor(Math.random() * N + 1); //产生1到10之间的随机数 var random = Math.floor(Math.random() * 10 + 1); //产生1到100之间的随机数 var random = Math.floor(Math.random() * 100 + 1);

  7 捕捉浏览器关闭的事件

  我们经常希望在用户关闭浏览器的时候,提示用户要保存尚未保存的东西,则下面的这个Javascript技巧是十分有用的,代码如下:

   ………

  就是编写onbeforeunload()事件的代码即可

  8 检查是否按了回退键

  同样,可以检查用户是否按了回退键,代码如下:

window.onbeforeunload = function() { return "You work will be lost."; };

  9 检查表单数据是否改变

  有的时候,需要检查用户是否修改了一个表单中的内容,则可以使用下面的技巧,其中如果修改了表单的内容则返回true,没修改表单的内容则返回false。代码如下:

function formIsDirty(form) { 
    for (var i = 0; i < form.elements.length; i++) { 
        var element = form.elements[i]; 
        var type = element.type; 
        if (type == "checkbox" || type == "radio") {
            if (element.checked != element.defaultChecked) {
                 return true; 
             } 
        } else if (type == "hidden" || type == "password" || type == "text" || type == "textarea") {
            if (element.value != element.defaultValue) {
                return true;
            } 
        } else if (type == "select-one" || type == "select-multiple") {
             for (var j = 0; j < element.options.length; j++) {
                  if (element.options[j].selected != element.options[j].defaultSelected) {
                       return true; 
                   } 
              } 
         } 
     } return false; 
    } window.onbeforeunload = function(e) {
     e = e || window.event; if (
     formIsDirty(document.forms["someForm"])) {
      // IE 和 Firefox if (e) { e.returnValue = "You have unsaved changes."; 
      } // Safari浏览器 return "You have unsaved changes."; 
      } 
      };

  10 完全禁止使用后退键

  下面的技巧放在页面中,则可以防止用户点后退键,这在一些情况下是需要的。代码如下:

  

  11 删除用户多选框中选择的项目

  下面提供的技巧,是当用户在下拉框多选项目的时候,当点删除的时候,可以一次删除它们,代码如下:

function selectBoxRemove(sourceID) { //获得listbox的id var src = document.getElementById(sourceID); //循环listbox for(var count= src.options.length-1; count >= 0; count--) { //如果找到要删除的选项,则删除 if(src.options[count].selected == true) { try { src.remove(count, null); } catch(error) { src.remove(count); } } } }

  12 Listbox中的全选和非全选

  如果对于指定的listbox,下面的方法可以根据用户的需要,传入true或false,分别代表是全选listbox中的所有项目还是非全选所有项目,代码如下:

function listboxSelectDeselect(listID, isSelect) { var listbox = document.getElementById(listID); for(var count=0; count < listbox.options.length; count++) { listbox.options[count].selected = isSelect; } }

  13 在Listbox中项目的上下移动

  下面的代码,给出了在一个listbox中如何上下移动项目

unction listbox_move(listID, direction) { var listbox = document.getElementById(listID); var selIndex = listbox.selectedIndex; if(-1 == selIndex) { alert("Please select an option to move."); return; } var increment = -1; if(direction == ''up'') increment = -1; else increment = 1; if((selIndex + increment) < 0 || (selIndex + increment) > (listbox.options.length-1)) { return; } var selValue = listbox.options[selIndex].value; var selText = listbox.options[selIndex].text; listbox.options[selIndex].value = listbox.options[selIndex + increment].value listbox.options[selIndex].text = listbox.options[selIndex + increment].text listbox.options[selIndex + increment].value = selValue; listbox.options[selIndex + increment].text = selText; listbox.selectedIndex = selIndex + increment; } //.. //.. listbox_move(''countryList'', ''up''); //move up the selected option listbox_move(''countryList'', ''down''); //move down the selected option

  14 在两个不同的Listbox中移动项目

  如果在两个不同的Listbox中,经常需要在左边的一个Listbox中移动项目到另外一个Listbox中去,下面是相关代码:

function listbox_moveacross(sourceID, destID) { var src = document.getElementById(sourceID); var dest = document.getElementById(destID); for(var count=0; count < src.options.length; count++) { if(src.options[count].selected == true) { var option = src.options[count]; var newOption = document.createElement("option"); newOption.value = option.value; newOption.text = option.text; newOption.selected = true; try { dest.add(newOption, null); //Standard src.remove(count, null); }catch(error) { dest.add(newOption); // IE only src.remove(count); } count--; } } } //.. //.. listbox_moveacross(''countryList'', ''selectedCountryList'');

  15 快速初始化Javscript数组

  下面的方法,给出了一种快速初始化Javscript数组的方法,代码如下:

var numbers = []; for(var i=1; numbers.push(i++)<100;); //numbers = [0,1,2,3 ... 100]

使用的是数组的push方法

  16 截取指定位数的小数

  如果要截取小数后的指定位数,可以使用toFixed方法,比如:

var num = 2.443242342;  alert(num.toFixed(2)); // 2.44 而使用toPrecision(x)则提供指定位数的精度,这里的x是全部的位数,如: num = 500.2349;  result = num.toPrecision(4);//输出500.2

  17 检查字符串中是否包含其他字符串

  下面的代码中,可以实现检查某个字符串中是否包含其他字符串。代码如下:

if (!Array.prototype.indexOf) { Array.prototype.indexOf = function(obj, start) { for (var i = (start || 0), j = this.length; i < j; i++) { if (this[i] === obj) { return i; } } return -1; } } if (!String.prototype.contains) { String.prototype.contains = function (arg) { return !!~this.indexOf(arg); }; }

  在上面的代码中重写了indexOf方法并定义了contains方法,使用的方法如下:

var hay = "a quick brown fox jumps over lazy dog"; var needle = "jumps"; alert(hay.contains(needle));

  18 去掉Javscript数组中的重复元素

  下面的代码可以去掉Javascript数组中的重复元素,如下:

function removeDuplicates(arr) { var temp = {}; for (var i = 0; i < arr.length; i++) temp[arr[i]] = true; var r = []; for (var k in temp) r.push(k); return r; } //用法 var fruits = [''apple'', ''orange'', ''peach'', ''apple'', ''strawberry'', ''orange'']; var uniquefruits = removeDuplicates(fruits); //输出的 uniquefruits [''apple'', ''orange'', ''peach'', ''strawberry''];

  19 去掉String中的多余空格

  下面的代码会为String增加一个trim()方法,代码如下:

if (!String.prototype.trim) { String.prototype.trim=function() { return this.replace(/^\s+|\s+$/g, ''''); }; } //用法 var str = " some string "; str.trim(); //输出 str = "some string"

  20 Javascript中的重定向

  在Javascript中,可以实现重定向,方法如下:

window.location.href = "http://viralpatel.net";

  21 对URL进行编码

  有的时候,需要对URL中的传递的进行编码,方法如下:

 var myOtherUrl = "http://example.com/index.html?url=" + encodeURIComponent(myUrl);


我们今天的关于41个Web开发者必须收藏的JavaScript实用技巧的分享已经告一段落,感谢您的关注,如果您想了解更多关于10 个适用于 JavaScript 开发的 IDE 新功能 | 实用技巧、20 个值得收藏的实用 JavaScript 技巧、2020最新JavaScript开发必须知道的41个技巧,你会几个?、21个值得收藏的Javascript技巧的相关信息,请在本站查询。

本文标签: