likes
comments
collection
share

优秀的js技巧方法

作者站长头像
站长
· 阅读数 2

优秀的js技巧方法

数组相关

声明和初始化数组

我们可以使用默认值(如""、null或 )初始化特定大小的数组0。您可能已经将这些用于一维数组,但如何初始化二维数组/矩阵呢?

const array = Array(5).fill(''); 
// 输出
(5) ["", "", "", "", ""]

const matrix = Array(5).fill(0).map(()=>Array(5).fill(0)); 
// 输出
(5) [Array(5), Array(5), Array(5), Array(5), Array(5)]
0: (5) [0, 0, 0, 0, 0]
1: (5) [0, 0, 0, 0, 0]
2: (5) [0, 0, 0, 0, 0]
3: (5) [0, 0, 0, 0, 0]
4: (5) [0, 0, 0, 0, 0]
length: 5

从数组中过滤出虚假值

Falsy值喜欢0undefinednullfalse""''可以很容易地通过以下方法省略

const array = [3, 0, 6, 7, '', false];
array.filter(Boolean);
// 输出
(3) [3, 6, 7]

数组查找

当对数组进行查找时,indexOf()用于获取查找项的位置。如果未找到该项,则返回值为-1。在JavaScript中,0被视为false,而大于或小于0的数字被视为true。因此,需要这样来写

传统写法:

if(arr.indexOf(item) > -1) { 
}

if(arr.indexOf(item) === -1) {
}

简化写法:

if(~arr.indexOf(item)) {
}

if(!~arr.indexOf(item)) {
}

位非(~)运算符对除了-1之外的任何值都返回一个"真"值。对其进行取反就是简单地使用!~即可。另外,也可以使用includes()函数:

if(arr.includes(item)) {
}

打乱数组

利用内置Math.random()方法。

const list = [1, 2, 3, 4, 5, 6, 7, 8, 9];
list.sort(() => {
    return Math.random() - 0.5;
});
// 输出
(9) [2, 5, 1, 6, 9, 8, 4, 3, 7]
// Call it again
(9) [4, 1, 7, 5, 3, 8, 2, 9, 6]

检测是否为一个安全数组

  // 检测是否为一个安全数组,若不是返回空数组  这里借助isArray 方法
  const safeArray = (array) => {
    return Array.isArray(array) ? array : []
  }

数组清空

  • 对比arr.length=0与arr=[]

arr.length=0的应用点主要是完全清空字面量指向的真实数组 我们知道在js中,引用类型相对应的自变量实际上是在栈内存中储存了地址,指向堆内存中真实的数据 假设现有一个不空的数组arr 当我们使用 arr=[]时,实际上是为arr重新赋值为一个空数组[] 此时arr原先储存的地址所指向的原数组仍然在内存中(可能导致内存泄露) 使用arr.length=0时:命令作用在真实数组,相当于直接将原数组清空

//使用arr作为模版用于循环中接收值:
res=arr
arr=[]
//等同于:
res=arr.slice()//copy
arr.length=0

实现并集、交集、和差集

let a = new Set([1, 2, 3]); 
let b = new Set([4, 3, 2]); 
// 并集 
let union = new Set([...a, ...b]); // Set {1, 2, 3, 4} 
// 交集 
let intersect = new Set([...a].filter(x => b.has(x))); // set {2, 3} 
// (a 相对于 b 的)差集 
let difference = new Set([...a].filter(x => !b.has(x))); // Set {1}

map循环

map: 只有当arr为基本数据类型时,map方法才不会改变原始数组,arr为引用类型时,还是会改变原数组的

const citys = [{ name: 'shenzhen' }, { name: 'hanghzhou' }];
const newCitys = citys.map((item) => {
    item.country = 'china';
    return item;
});
 console.log('citys', citys); //[{ name: 'shenzhen', country: 'china' },{ name: 'hanghzhou', country: 'china' }]
 console.log('newCitys', newCitys); //[{ name: 'shenzhen', country: 'china' },{ name: 'hanghzhou', country: 'china' }]

逻辑运算

对各种条件使用逻辑运算符

如果你想减少嵌套 if…else 或 switch case,你可以简单地使用基本的逻辑运算符AND/OR

function doSomething(arg1){ 
    arg1 = arg1 || 10; 
// 如果尚未设置,则将 arg1 设置为 10 作为默认值
return arg1;
}

let foo = 10;  
foo === 10 && doSomething(); 
// is the same thing as if (foo == 10) then doSomething();
// 输出: 10

foo === 5 || doSomething();
// is the same thing as if (foo != 5) then doSomething();
// 输出: 10

可选链

可选的链接 ?.如果值在 ? 之前,则停止评估。为 undefined 或 null 并返回

undefined
const user = {
  employee: {
    name: "Kapil"
  }
};
user.employee?.name;
// 输出: "Kapil"
user.employ?.name;
// 输出: undefined
user.employ.name
// 输出: VM21616:1 Uncaught TypeError: Cannot read property 'name' of undefined

对于动态属性将其更改为:

object?.[index] 

对于方法的调用你可以这样写

object.runsOnlyIfMethodExists?.()

空合并算子

空合并运算符 (??) 是一个逻辑运算符,当其左侧操作数为空或未定义时返回其右侧操作数,否则返回其左侧操作数。

const foo = null ?? 'my school';
// 输出: "my school"

const baz = 0 ?? 42;
// 输出: 0

||=与??=

||=??= 是两种不同的赋值运算符,它们分别表示逻辑或赋值和空值合并赋值。

  • ||= 运算符用于给变量赋值,但仅当左侧的变量为假值(false、null、undefined、空字符串等)时才会执行赋值操作。

  • 例如:

let x = null;
x ||= 5;
console.log(x);  // 输出 5,因为 x 是 null,所以赋值为 5

let y = 10;
y ||= 7;
console.log(y);  // 输出 10,因为 y 已经有值了,不会执行赋值操作
  • ??= 运算符用于给变量赋值,但仅当左侧的变量为 nullundefined 时才会执行赋值操作。

  • 例如:

javascriptCopy Codelet a = null;
a ??= 5;
console.log(a);  // 输出 5,因为 a 是 null,所以赋值为 5

let b = 10;
b ??= 7;
console.log(b);  // 输出 10,因为 b 已经有值了,不会执行赋值操作

数字相关

将十进制转换为二进制或十六进制

在解决问题的同时,我们可以使用一些内置的方法,例如.toPrecision().toFixed()来实现许多帮助功能。

const num = 10;

num.toString(2);
// 输出: "1010"
num.toString(16);
// 输出: "a"
num.toString(8);
// 输出: "12"

获取两个整数之间的随机整数

该方法用于获取两个整数之间的随机整数

const random = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);

random(1, 50);

将一个字符串变成数字

常规操作

let str = '2'
console.log(Number(str))   //2
复制代码

骚操作一

let str = '2'
console.log(~~str)    //2

骚操作二

let str = '2'
console.log(+str)    //2

科学计数法

可以使用科学技术法来表示数字,以省略尾部的零。例如,1e7 实际上表示 1 后面跟着 7 个零。它表示一个十进制,相当于 10,000,000。

传统写法:

for (let i = 0; i < 10000; i++) {}

简化写法:

for (let i = 0; i < 1e7; i++) {}

// 下面的所有比较都将返回 true
1e0 === 1;
1e1 === 10;
1e2 === 100;
1e3 === 1000;
1e4 === 10000;
1e5 === 100000;

指数幂运算

指数幂运算可以使用 ** 来简化。

传统写法:

Math.pow(2,3); // 8
Math.pow(2,2); // 4
Math.pow(4,3); // 64

简化写法:

2**3 // 8
2**4 // 4
4**3 // 64

从 ES7(ECMAScript 2016)开始,JavaScript 引入了指数幂运算符 **,使指数幂运算更加简洁。

转为布尔值

可以使用双重逻辑非操作符将任何值转换为布尔值。

!!23 // TRUE
!!"" // FALSE
!!0 // FALSE
!!{} // TRUE

单一的逻辑非操作符已经可以将值转换为布尔类型并对其进行取反,所以第二个逻辑非操作符会再次对其进行取反,从而将其恢复为原始含义,并保持为布尔类型。

对象相关

检查对象是否为空

检查对象是否为空,实际上并不那么简单,即使对象为空,每次检查对象是否等于 {} 也会返回 false

幸运的是,下面的单行代码正是我们想要的。

const isEmpty = obj => Reflect.ownKeys(obj).length === 0 && obj.constructor === Object;
isEmpty({}) // true
isEmpty({a:"not empty"}) //false

动态属性名称:多功能对象键

可以使用方括号将变量用作对象属性名称:

const key = 'name';  
const person = { [key]: 'Alice' };  
console.log(person.name); // Output: Alice

检测对象是否为一个安全对象

    // 首先要去判断 当前对象是否为有效对象 
    const isVaildObject = (obj) => {
        return typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length
    }
    // 这里直接用上面的函数 如果有效就返回本身,无效就返回空对象
    const safeObject = obj => isVaildObject(obj) ? obj : {}
    

字符串相关

字符串首字母大写

该方法用于将英文字符串的首字母大写处理:

const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)

capitalize("hello world")  // Hello world

翻转字符串

该方法用于将一个字符串进行翻转操作,返回翻转后的字符串:

const reverse = str => str.split('').reverse().join('');

reverse('hello world');   // 'dlrow olleh'

过滤特殊字符

    function filterCharacter(str){
        // 首先设置一个模式
        let pattern = new RegExp("[`~!@#$^&*()=:”“'。,、?|{}':;'%,\[\].<>/?~!@#¥……&*()&;—|{ }【】‘;]")
        let resultStr = "";
        for (let i = 0; i < str.length; i++) {
            // 主要通过 replace ,pattern 规则 去把字符替换成空 最后拼接在 resultStr
            resultStr = resultStr + str.substr(i, 1).replace(pattern, '');
        }
        // 当循环结束的时候返回最后结果 resultStr
        return resultStr;
    }
    
    // 示例
    filterCharacter('gyaskjdhy12316789#$%^&!@#1=123,./[') // 结果:gyaskjdhy123167891123

浏览器相关

复制内容到剪切板

该方法使用 navigator.clipboard.writeText 来实现将文本复制到剪贴板:

const copyToClipboard = (text) => navigator.clipboard.writeText(text);

copyToClipboard("Hello World");

兼容性方案

const copyText = async (val) => {
  try {
    // 使用现代 API 尝试复制
    if (navigator.clipboard && navigator.permissions) {
      await navigator.clipboard.writeText(val);
      return; // 如果成功,直接返回
    }

    // 降级方案
   const textArea = document.createElement('textArea') 
   textArea.value = val 
   textArea.style.width = 0 
   textArea.style.position = 'fixed' 
   textArea.style.left = '-999px' 
   textArea.style.top = '10px' 
   textArea.setAttribute('readonly', 'readonly')
   document.body.appendChild(textArea) 
   textArea.select()

    // 尝试执行复制操作
    const success = document.execCommand('copy');
    if (!success) {
      throw new Error('无法复制文本');
    }

    // 清理
    document.body.removeChild(textArea);
  } catch (err) {
    console.error('复制失败:', err);
  }
};

清除所有cookie

该方法可以通过使用 document.cookie 来访问 cookie 并清除存储在网页中的所有 cookie:

const clearCookies = document.cookie.split(';').forEach(
                    cookie => document.cookie = cookie.replace(/^ +/,'')
                    .replace(/=.*/, `=;expires=${new Date(0).toUTCString()};path=/`));

获取选中的文本

该方法通过内置的 getSelection 属性获取用户选择的文本:

const getSelectedText = () => window.getSelection().toString();

getSelectedText();

滚动到页面顶部

该方法用于在页面中返回顶部:

const goToTop = () => window.scrollTo(0, 0);
// function goTop() { window.scrollTo({ top: 0, behavior: "smooth" }); }

goToTop();

是否滚动到页面底部

该方法用于判断页面是否已经底部:

const scrolledToBottom = () => document.documentElement.clientHeight + window.scrollY
                                        >= document.documentElement.scrollHeight;

判断当前标签页是否激活

该方法用于检测当前标签页是否已经激活:

const isTabInView = () => !document.hidden; 

重定向到一个URL

该方法用于重定向到一个新的URL:

const redirect = url => location.href = url

redirect("https://www.google.com/")

打开浏览器打印框

该方法用于打开浏览器的打印框: js

const showPrintDialog = () => window.print()

检测元素是否处于焦点

activeElement 属性返回文档中当前获得焦点的元素。

const elementIsInFocus = (el) => (el === document.activeElement);

elementIsInFocus(anyElement)
// 元素处于焦点返回true,反之返回false

url相关

从url获取参数并转为对象

网页路径经常是:www.baidu.com?search=js&xxx=kkk这种形式的,我们是经常需要取参数的,可以使用第三方的qs包实现,如果你只是要实现去参数,这一句代码就可以实现,不用再引入qs了。

const getParameters = URL => JSON.parse(`{"${decodeURI(URL.split("?")[1]).replace(/"/g, '\"').replace(/&/g, '","').replace(/=/g, '":"')}"}`
  )

getParameters("https://www.google.com.hk/search?q=js+md&newwindow=1");
// {q: 'js+md', newwindow: '1'}

重定向到一个URL

该方法用于重定向到一个新的URL:

const redirect = url => location.href = url

redirect("https://www.google.com/")

其他

检测是否是一个函数

    // 检测是否是一个函数  其实写法以后直接 isFunction 就好了,避免重复写判断
    const isFunction = (obj) => {
        return typeof obj === "function" && typeof obj.nodeType !== "number" && typeof obj.item !== "function";
    };

防抖/节流

简单介绍

  • 防抖:指定时间内 频繁触发一个事件,以最后一次触发为准
  • 节流:指定时间内 频繁触发一个事件,只会触发一次

应用场景有很多比如:

防抖是: input搜索,用户在不断输入内容的时候,用防抖来减少请求的次数并且节约请求资源

节流:场景普遍就是按钮点击,一秒点击 10 下会发起 10 次请求,节流以后 1 秒点再多次,都只会触发一次

下面我们来实现

    // 防抖
    // fn 需要防抖的函数,delay 为定时器时间
    function debounce(fn,delay){
        let timer =  null  // 用于保存定时器
        return function () { 
            // 如果timer存在 就清除定时器,重新计时
            if(timer){
                clearTimeout(timeout);
            }
            //设置定时器,规定时间后执行真实要执行的函数
            timeout = setTimeout(() => {
               fn.apply(this);
            }, delay);
        }
    }
    
    // 节流
    function throttle(fn) {
      let timer = null; // 首先设定一个变量,没有执行定时器时,默认为 null
      return function () {
        if (timer) return; // 当定时器没有执行的时候timer永远是false,后面无需执行
        timer = setTimeout(() => {
          fn.apply(this, arguments);
           // 最后在setTimeout执行完毕后再把标记设置为true(关键)
           // 表示可以执行下一次循环了。
          timer = null;
        }, 1000);
      };
    }

常用正则判断

    // 校验2-9位文字 不符合为 false  符合为 true
    const validateName = (name) => {
      const reg = /^[\u4e00-\u9fa5]{2,9}$/;
      return reg.test(name);
    };

    // 校验手机号
    const validatePhoneNum = (mobile) => {
      const reg = /^1[3,4,5,6,7,8,9]\d{9}$/;
      return reg.test(mobile);
    };

    // 校验6到18位大小写字母数字下划线组成的密码
    const validatePassword = (password) => {
      const reg = /^[a-zA-Z0-9_]{6,18}$/;
      return reg.test(password);
    };

高级技巧

模拟点击

vue.js

1,给另一个按钮添加ref

<el-button size="small" type="primary" ref="import">导入</el-button>

2,事件触发

this.$refs.import.$el.click()

利用函数给对象赋值

eventDic.closeCase = (() => {
    var ary = e.applicationSettle ? e.applicationSettle.split(',') : []
    var dary = ary.map(o => this.eventDict.applicationSettle.get(o))
    return dary.join(',')
})()

 酷炫控制台技巧:调试的乐趣

使用console.table()console.groupCollapsed()超越console.log()

const users = [{ name'Alice' }, { name'Bob' }];  
console.table(users);  
console.groupCollapsed(’Details’);  
console.log(’NameAlice’);  
console.log(’Age30’);  
console.groupEnd();

编码好习惯

console.log({name})取代console.log('name', name)

当我们有一个变量名需要在控制台打印的时候,很多人都习惯于这样写:

console.log('name', name)

这种写法本身没有问题,但是会有一些小问题:

  1. 代码长度较长,字符串无法自动补全需要复制粘贴,变量名较长的情况更为明显。
  2. 表现不直观,如果name是一个对象,展开的时候占位太高我们会经常找不到开头的name在哪。

有了ES6,我们其实完全可以这样写:

console.log({name})

这种写法在结果上,可以和上面的写法达到一样的目的。但是不管是代码简洁程度、还是可读性上,都可以得到更友好的提升。尤其是name是一个对象的时候,效果更为明显。

虽然是很简单的一行代码,但是效果还是比较实用的。

巧用JS隐式类型转换

JS是一门弱类型语言,不同type的变量可以相互转化。我们可以巧妙的利用这一特性,让我们的代码在做类型转换的时候,变得更简洁更优雅。直接上代码:

  • 快速转换Number类型:
// 字符串转数字代码对比 

const price = parseInt('32'); //传统方式
const price = Number('32'); //传统方式

const price = +'32'; //新方式

// 日期转换为时间戳代码对比 

const timeStamp = new Date().getTime(); //传统方式
const timeStamp = +new Date(); //新方式

//布尔转数字新方式
 console.log(+true); // Return: 1
 console.log(+false); // Return: 0
  • 快速转换Boolean类型:
// 各种类型转布尔代码对比 

const isTrue = Boolean('') //传统方式
const isTrue = !!'' //新方式

const isTrue = Boolean(0) //传统方式
const isTrue = !!0 //新方式

const isTrue = Boolean(null) //传统方式
const isTrue = !!null //新方式

const isTrue = Boolean(undefined) //传统方式
const isTrue = !!undefined //新方式
  • 快速转换String类型:
// 数字转string代码对比
const num = 1;

const str = num.toString(); //传统方式
const str = num + ''; //新方式

return取代if...else

假如我们有以下代码:

if (condition1) {
  // do condition1 
} else if (condition2) {
  // do condition2
} else if(condition3) {
  // do condition3
}

这个写法逻辑上没有问题,但是当日后if条件增加的时候,越来越多的if else 阅读起来费劲不说,更难受的是,当我们需要删除一个条件的时候,我们需要很小心的找到每一个if else对应的{},更没办法直接选中代码直接删除。其实我们完全可以改成return形式让代码变得更简洁、更易读,且更容易编辑

if (condition1) {
  // do condition1 
  return;
}

if (condition2) {
  // do condition2
  return;
}

if (condition3) {
  // do condition3  
  return;
}

可能你会说,这么简单的东西,还要写出来,谁不会呢?

但是看起来是很简单,大家都一眼就能看懂的改动,其实根据笔者的经验,很多有经验的老手,都会时常忘记这个小细节。