重学JS-技巧篇
对象处理
创建一个绝对空的对象
let vehical = Object.create(null);
从对象中选择特定数据
var selectObj = (obj, items) => {
return items.reduce((result, item) => {
result[item] = obj[item];
return result;
}, {});
};
var vehicle = { brand: "BWM", year: 2022, type: "suv" };
var selected = selectObj(vehicle, ["brand", "type"]);
console.log(selected);
从对象中删除键
var remove = (object, removeList = []) => {
var result = { ...object };
removeList.forEach((item) => {
delete result[item];
});
return result;
};
var vehicle = { brand: "BWM", year: 2022, type: "suv" };
var itemRemoved = remove(vehicle, ["year"]);
console.log(itemRemoved);
将对象数据拉入数组
var vehicle = { brand: "BWM", year: 2022, type: "suv" };
console.log(Object.entries(vehicle));
有条件地向对象添加属性
const type = { type: "suv" };
const vehicle = {
brand: "BMW",
year: 2022,
...(!type ? {} : type),
};
console.log(vehicle);
调试技巧
设置断点
在代码行设置断点
设置代码行断点的步骤:
● 单击切换到 Sources 选项卡;
● 从文件导航部分选中需要调试的源文件;
● 在右侧代码编辑器区域找到需要调试的代码行;
● 单击行号以在行上设置断点。
设置条件断点
设置条件断点的步骤:
● 单击切换到 Sources 选项卡;
● 从文件导航部分选中需要调试的源文件;
● 在右侧代码编辑器区域找到需要调试的代码行;
● 右键单击行号并选择"Add conditional breakpoint"来添加条件断点
在事件监听器上设置断点
在事件监听器上设置断点的步骤:
● 单击切换到 Sources 选项卡;
● 在debugger区域展开Event Listener Breakpoints选项;
● 从事件列表中选择事件监听器来设置断点。我们的程序中有一个按钮单击事件,这里就选择 Mouse事件选项中的click。
在 DOM 节点中设置断点
DevTools 在 DOM 检查和调试方面同样很强大。当在 DOM 中添加、删除或者修改某些内容时,可以设置断点来暂停代码的执行。
在 DOM 上设置断点的步骤:
● 单击切换到 Elements 选项卡;
● 找到要设置断点的元素;
● 右键单击元素以获得上下文菜单,选择Break on选项,然后选择Subtree modifications、Attribute modifications、Node removal中的一个即可:
这三个选项的含义如下:
● Subtree modifications:当节点内部子节点变化时断点;
● Attribute modifications:当节点属性发生变化时断点;
● Node removal:当节点被移除时断点。
逐步调试
下一步(快捷键:F9)
此选项使我们能够在JavaScript代码执行时逐行执行,如果中途有函数调用,单步执行也会进入函数内部,逐行执行,然后退出。
跳过(快捷键:F10)
此选项允许我们在执行代码时跳过一些代码。有时我们可能已经确定某些功能是正常的,不想花时间去检查它们,就可以使用跳过选项。
进入(快捷键:F11)
使用该选项可以更深入的了解函数。单步执行函数时,当感觉某个函数的行为异常并想检查它时,就可以使用这个选项来进入函数内部并进行调试。
跳出(快捷键:Shift+F11)
在单步执行一个函数时,我们可能不想再继续执行并退出它,就可以使用这些选项退出函数。
跳转(快捷键:F8)
有时,我们希望从一个断点跳转到另一个断点,而无需在它们之间进行任何调试,就可以使用这个选项来跳转到下一个断点:
命名约定
let dogName = 'Droopy';
let hasOwner = true;
function getName{ }
const LEG = 4;
class DogName { }
<div>
<DogCartoon roles={{ dogName: 'Scooby-Doo', ownerName: 'Shaggy' }} />
</div>
class DogCartoon {
constructor(dogName, ownerName) {
this.dogName = dogName;
this.ownerName = ownerName;
}
getName() {
return '${this.dogName} ${this.ownerName}';
}
}
const cartoon = new DogCartoon('Scooby-Doo', 'Shaggy');
console.log(cartoon.getName());
class DogCartoon {
constructor(dogName, ownerName) {
this.dogName = dogName;
this.ownerName = ownerName;
this.name = _toonName(dogName, ownerName);
}
_toonName(dogName, ownerName) {
return `${dogName} ${ownerName}`;
}
}
开发技巧
计算代码性能
var startTime = performance.now();
for (let i = 0; i < 1000; i++) {
console.log(i);
}
var endTime = performance.now();
var totaltime = endTime - startTime;
console.log(totaltime);
验证 undefined 和 null
if (a === null || a === undefined) {
doSomething();
}
a ?? doSomething();
对象动态声明属性
var dynamic = "color";
var item = {
brand: "Ford",
[dynamic]: "Blue",
};
console.log(item);
缩短 console.log()
var c = console.log.bind(document);
c(996);
c("hello world");
数字取整
~~3.1415926;
23.9 | 0;
-23.9 | 0;
使用 switch case 替换 if/else
if (1 == month) {
days = 31;
} else if (2 == month) {
days = IsLeapYear(year) ? 29 : 28;
} else if (3 == month) {
days = 31;
} else if (4 == month) {
days = 30;
} else if (5 == month) {
days = 31;
} else if (6 == month) {
days = 30;
} else if (7 == month) {
days = 31;
} else if (8 == month) {
days = 31;
} else if (9 == month) {
days = 30;
} else if (10 == month) {
days = 31;
} else if (11 == month) {
days = 30;
} else if (12 == month) {
days = 31;
}
switch (month) {
case 1:
days = 31;
break;
case 2:
days = IsLeapYear(year) ? 29 : 28;
break;
case 3:
days = 31;
break;
case 4:
days = 30;
break;
case 5:
days = 31;
break;
case 6:
days = 30;
break;
case 7:
days = 31;
break;
case 8:
days = 31;
break;
case 9:
days = 30;
break;
case 10:
days = 31;
break;
case 11:
days = 30;
break;
case 12:
days = 31;
break;
default:
break;
}
获取数组中的最后一项
var arr = [1, 2, 3, 4, 5];
arr[arr.length - 1];
arr.slice(-1)[0];
arr.slice(-2)[(4, 5)];
空值合并运算符:??
let grade = 0;
console.log(grade || 100);
console.log(grade ?? 100);
内存使用
var data = [
{ name: "Frogi", type: Type.Frog },
{ name: "Mark", type: Type.Human },
{ name: "John", type: Type.Human },
{ name: "Rexi", type: Type.Dog },
];
var mappedArr = data.map((entity) => {
return {
...entity,
walkingOnTwoLegs: entity.type === Type.Human,
};
});
var tooManyTimesMappedArr = mappedArr.map((entity) => {
return {
...entity,
greeting: entity.type === Type.Human ? "hello" : "none",
};
});
console.log(tooManyTimesMappedArr);
var mappedArr = data
.map((entity) => {
return {
...entity,
walkingOnTwoLegs: entity.type === Type.Human,
};
})
.map((entity) => {
return {
...entity,
greeting: entity.type === Type.Human ? "hello" : "none",
};
});
var mappedArr = data.map((entity) =>
entity.type === Type.Human
? {
...entity,
walkingOnTwoLegs: true,
greeting: "hello",
}
: {
...entity,
walkingOnTwoLegs: false,
greeting: "none",
}
);
function findCities(country) {
switch (country) {
case "Russia":
return ["Moscow", "Saint Petersburg"];
case "Mexico":
return ["Cancun", "Mexico City"];
case "Germany":
return ["Munich", "Berlin"];
default:
return [];
}
}
var citiesCountry = {
Russia: ["Moscow", "Saint Petersburg"],
Mexico: ["Cancun", "Mexico City"],
Germany: ["Munich", "Berlin"],
};
function findCities(country) {
return citiesCountry[country] ?? [];
}
console.log(findCities(null));
console.log(findCities("Germany"));
var citiesCountry = new Map()
.set("Russia", ["Moscow", "Saint Petersburg"])
.set("Mexico", ["Cancun", "Mexico City"])
.set("Germany", ["Munich", "Berlin"]);
function findCities(country) {
return citiesCountry.get(country) ?? [];
}
console.log(findCities(null));
console.log(findCities("Germany"));
单行代码
日期处理
var isDateValid = (...val) => !Number.isNaN(new Date(...val).valueOf());
isDateValid("December 17, 1995 03:24:00");
isDateValid("December 77, 1995 03:24:00");
var dayDif = (date1, date2) => Math.ceil(Math.abs(date1.getTime() - date2.getTime()) / (1000 * 60 * 60 * 24));
dayDif(new Date("2021-11-3"), new Date("2022-2-1"))
var dayOfYear = (date) => Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24)
dayOfYear(new Date());
var timeFromDate = date => date.toTimeString().slice(0, 8);
timeFromDate(new Date(2021, 11, 2, 12, 30, 0));
timeFromDate(new Date());
字符串处理
var capitalize = str => str.charAt(0).toUpperCase() + str.slice(1)
capitalize("hello world")
var reverse = str => str.split('').reverse().join('');
reverse('hello world');
var randomString = () => Math.random().toString(36).slice(2);
randomString();
var truncateString = (string, length) => string.length < length ? string : `${string.slice(0, length - 3)}...`
truncateString('aafgadgsdgsdfghf', 10);
var stripHtml = html => (new DOMParser().parseFromString(html, 'text/html')).body.textContent || ''
stripHtml('aaaa<div>dada</div>')
数组处理
var removeDuplicates = (arr) => [...new Set(arr)];
console.log(removeDuplicates([1, 2, 2, 3, 3, 4, 4, 5, 5, 6]));
var isNotEmpty = arr => Array.isArray(arr) && arr.length > 0;
isNotEmpty([1, 2, 3]);
var merge = (a, b) => a.concat(b);
var merge = (a, b) => [...a, ...b];
数字操作
var isEven = num => num % 2 === 0;
isEven(996);
var average = (...args) => args.reduce((a, b) => a + b) / args.length
average(1, 2, 3, 4, 5);
var random = (min, max) => Math.floor(Math.random() * (max - min + 1) + min)
random(1, 50);
var round = (n, d) => Number(Math.round(n + "e" + d) + "e-" + d)
round(1.005, 2)
round(1.555, 2)
颜色操作
var rgbToHex = (r, g, b) => "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
rgbToHex(255, 255, 255);
var randomHex = () => `#${Math.floor(Math.random() * 0xffffff).toString(16).padEnd(6, '0')}`;
randomHex();
浏览器操作
var copyToClipboard = (text) => navigator.clipboard.writeText(text);
copyToClipboard("Hello World");
const clearCookies = document.cookie.split(';').forEach(cookie => { document.cookie = cookie.replace(/^ +/, '').replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`); });
其他操作
ESLint 异步
异步代码的ESLint规则
new Promise(async (resolve, reject) => { });
new Promise((resolve, reject) => { });
for (var url of urls) {
var response = await fetch(url);
}
var responses = [];
for (var url of urls) {
var response = fetch(url);
responses.push(response);
}
await Promise.all(responses);
new Promise((resolve, reject) => {
return result;
});
new Promise((resolve, reject) => {
resolve(result);
});
let totalPosts = 0;
async function getPosts(userId) {
var users = [{ id: 1, posts: 5 }, { id: 2, posts: 3 }];
return users.find((user) => user.id === userId).posts;
}
async function addPosts(userId) {
totalPosts += await getPosts(userId);
}
await Promise.all([addPosts(1), addPosts(2)]);
console.log('Post count:', totalPosts);
async () => {
return await getUser(userId);
}
async () => {
return getUser(userId);
}
async () => {
try {
return await getUser(userId);
} catch (error) {
}
}
async () => {
try {
var user = await getUser(userId);
return user;
} catch (error) {
}
}
Promise.reject('An error occurred');
Promise.reject(new Error('An error occurred'));
Node.js 特定规则
function callback(err, data) {
console.log(data);
}
function callback(err, data) {
if (err) {
console.log(err);
return;
}
console.log(data);
}
cb('An error!');
callback(result);
cb(new Error('An error!'));
callback(null, result);
var file = fs.readFileSync(path);
var file = await fs.readFile(path);
TypeScript 特定规则
function getValue() {
return someValue;
}
await getValue();
async function getValue() {
return someValue;
}
await getValue();
myPromise()
.then(() => { });
myPromise()
.then(() => { })
.catch(() => { });
if (getUserFromDB()) { }
if (await getUserFromDB()) { }
const user = await getUserFromDB();
if (user) { }
function doSomething() {
return somePromise;
}
async function doSomething() {
return somePromise;
}