提升效率的41个JavaScript开发技巧

目录
文章目录隐藏
  1. 前言
  2. Array
  3. Object
  4. Function
  5. Number
  6. Boolean
  7. 结语

前言

JavaScript 语言是我们前端开发的核心技能,不管市面上如何更新迭代新的编程语言或者是出现新的前端框架等,都离不开基础的 JS 语言,所以作为一个前端开发会 JS 是我们必备技能,然而我发现很多小伙伴 JS 会用,却用的不是很巧妙,在编写过程中导致大量冗余代码出现,所以我特此整理此篇文章为需要的小伙伴提供参考,希望那个对大家有用。文章内容有点长,建议先马后看(CTRL + D)。

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 }]

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 result = [];
arr.forEach(item => {
	!result.some(v => JSON.stringify(v) === JSON.stringify(item)) && result.push(item)
})
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.数组求和

普通数组

const arrSum = [1, 2, 3, 4].reduce(function(prev, cur) {
	return prev + cur;
}, 0)
console.log(arrSum)//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 = [].concat.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)//true

11.数组每一项都满足

普通数组

const arr = [1, 2, 3].every(item => {
	return item > 2
})
console.log(arr)//false

数组对象

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

12.数组有一项满足

普通数组

const arr = [1, 2, 3].some(item => {
	return item > 2
})
console.log(arr)//true

数组对象

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.1000', '1.1', '1.25', '1.40', '1.5', '1.5' ]
console.log(b.sort(sortNumber)); //[ 1, 2, 3, 5, 6, 7 ]

可见 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
};
console.log(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)); // "321recuder"

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"

方法二:

console.log('1234567890'.replace(/\B(?=(\d{3})+(?!\d))/g, ","))
console.log((1234567890).toLocaleString())

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['张三'])

结语

以上就是为大家带来的 41 个 JavaScript 开发技巧,文章持续更新,整理不易,感谢阅读,感谢分享!

推荐阅读:前端开发必会的 14 个 JavaScript 调试技巧

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
码云笔记 » 提升效率的41个JavaScript开发技巧

发表回复