目录
Map 介绍
语法
array.map(callback[, thisArg])
参数
callback
原数组中的元素经过该方法后返回一个新的元素。
currentValue
callback 的第一个参数,数组中当前被传递的元素。
index
callback 的第二个参数,数组中当前被传递的元素的索引。
array
callback 的第三个参数,调用 map 方法的数组。
thisArg
执行 callback 函数时 this 指向的对象。
返回值
由回调函数的返回值组成的新数组。
例题
https://www.codewars.com/kata/double-char
Given a string, you have to return a string in which each character (case-sensitive) is repeated once.
doubleChar("String") ==> "SSttrriinngg"
doubleChar("Hello World") ==> "HHeelllloo WWoorrlldd"
doubleChar("1234!_ ") ==> "11223344!!__ "
Good Luck!
答案:
const doubleChar = (str) =>
str
.split('')
.map((i) => i.repeat(2))
.join('');
Reduce 介绍
语法
arr.reduce(callback, [initialValue]);
参数
callback
执行数组中每个值的函数,包含四个参数:
accumulator
上一次调用回调返回的值,或者是提供的初始值(initialValue)
currentValue
数组中正在处理的元素
currentIndex
数据中正在处理的元素索引,如果没有提供 initialValues,默认从 0 开始
array
调用 reduce 的数组
initialValue
作为第一次调用 callback 的第一个参数。
返回值
函数累计处理的结果。
例题
https://www.codewars.com/kata/beginner-reduce-but-grow
Given and array of integers (x), return the result of multiplying the values together in order. Example:
[1, 2, 3] --> 6
For the beginner, try to use the reduce method - it comes in very handy quite a lot so is a good one to know.
Array will not be empty.
答案:
const grow = (x) => x.reduce((r, i) => r * i, 1);
正则替换
参考:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp
工具:
- RegExp tester (Chrome 插件)
例题
Write a function that accepts an array of 10 integers (between 0 and 9), that returns a string of those numbers in the form of a phone number.
Example:
createPhoneNumber([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) // => returns "(123) 456-7890"
The returned format must be correct in order to complete this challenge.
Don’t forget the space after the closing parenthese!
题目地址: https://www.codewars.com/kata/create-phone-number
答案:
const createPhoneNumber = (n) => n.join('').replace(/(\d{3})(\d{3})(\d{3})/, '($1) $2-$3');
异常捕获
ES5 中的传统做法
假设代码块执行抛出错误 fail,那么捕获该错误的写法为:
try {
// 代码块执行,并抛出 fail 错误
throw new Error('fail');
} catch (e) {
console.log(e);
}
定时器
我们先来针对上面的代码改写一下,加入一个定时器。
try {
setTimeout(() => {
throw new Error('fail');
// Uncaught Error: fail
}, 1000);
} catch (e) {
console.log(e);
}
像这样,将 try/catch 扔在定时器的外面,是无法捕获到内部的错误的。
正确的做法应该是:
setTimeout(() => {
try {
throw new Error('fail');
} catch (e) {
console.log(e);
}
}, 1000);
Promise
function doSomething() {
return new Promise((resolve, reject) => {
// 同步代码中的 throw 可以被捕捉到
throw new Error('fail');
});
}
doSomething()
.then((x) => {
console.log('success:', x);
})
.catch((err) => {
console.log('fail:', err);
});
这样写是没有问题的,错误能够被捕获到。但只要稍微修改一下,可能就出现问题了。比如:
function doSomething() {
return new Promise((resolve, reject) => {
// 异步代码中的 throw 不能被 Promise 的 catch 捕捉到
setTimeout(() => {
throw new Error('fail');
}, 1000);
});
}
doSomething()
.then((x) => {
console.log('success:', x);
})
.catch((err) => {
console.log('fail:', err);
});
这里抛出但错误将不能被捕获。所以,在 Promise 中,我们一般通过 reject 来抛出错误。
function doSomething(x) {
return new Promise((resolve, reject) => reject(x));
}
doSomething('fail')
.then((x) => {
console.log('success:', x);
})
.catch((err) => {
console.log('fail:', err);
});
// fail: fail
另外,还有一个比较有意思的细节,在 catch 之后继续添加 .then 会被继续执行。
function doSomething(x) {
return new Promise((resolve, reject) => reject(x));
}
doSomething('fail')
.then((x) => {
console.log('success:', x);
})
.catch((err) => {
console.log('fail:', err);
// 这里可以写 return 给下面的方法继续执行
})
.then((x) => {
console.log('continue:', x);
});
// fail: fail
// continue: undefined
Async/Await
本质上来讲, Async/Await 是通过 Promise 实现,所以基本跟上面 Promise 所讲的差不多。
可以在 await 方法外嵌套 try/catch,类似这样:
function doSomething(x) {
return new Promise((resolve, reject) => reject(x));
}
(async () => {
try {
const result = await doSomething('fail');
console.log('success:', result);
// return 返回
} catch (err) {
console.log('fail:', err);
// return 返回
}
})();
// fail: fail
但这里就有一个问题,比如函数需要有返回,那么返回的语句就需要写两次,正常但时候返回结果,错误的时候,返回一个 throw new Error()
或者其他的。有一个小的窍门,可以这样写:
function doSomething(x) {
return new Promise((resolve, reject) => reject(x));
}
(async () => {
const result = await doSomething('fail').catch((err) => {
console.log('fail:', err);
return 0; // 默认值
});
console.log('success:', result);
})();
// fail: fail
// success: 0
在错误捕获到之后,重新分配一个默认值,让代码继续运行。
事件委派
如对 AJAX 请求返回结果中的按钮进行 click
事件绑定:
var handleClick = function (e) {
if (e.target && e.target.nodeName.toLowerCase() === 'button') {
// Codes Here
}
};
parentNode.addEventListener('click', handleClick);
Deep Clone
问题现象:
var obj1 = {
key1: 'value1',
key2: 'value2',
children: {
key3: 'value3',
key4: 'value4'
}
};
var obj2 = Object.assign({
}, obj1);
obj2.children.key3 = 'test';
console.log(obj1.children);
// { key3: 'test', key4: 'value4' }
快速解决方案:
const obj2 = JSON.parse(JSON.stringify(obj1));
Scroll Debounce
用于解决前端滚动侦听事件触发频率过高问题。
核心代码:
function debounce(func, wait = 20, immediate = true) {
var timeout;
return function () {
var context = this,
args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
示例代码:
function testFunc(e) {
console.count(e);
}
window.addEventListener('scroll', () => console.count('bounce'));
window.addEventListener('scroll', debounce(testFunc));
在浏览器中测试。
遍历用 Map 还是 For
同是遍历,但实际有很大不同。
对比
map
改变自身。
[1, 2, 3, 4, 5].map((x) => x + 1);
// [ 2, 3, 4, 5, 6 ]
for
只是循环。
Benchmark 测试
benchmark 脚本:
suite('iterator', function () {
bench('for', function () {
const a = [1, 2, 3, 4, 5];
for (let i = 0; i < a.length; i++) {
// nothing
}
});
bench('foreach', function () {
const a = [1, 2, 3, 4, 5];
a.forEach(function (d) {
// nothing
});
});
bench('for of', function () {
const a = [1, 2, 3, 4, 5];
for (let i of a) {
// nothing
}
});
bench('map', function () {
const a = [1, 2, 3, 4, 5];
a.map((x) => x);
});
});
测试结果:
iterator
50,038,931 op/s » for
8,980,276 op/s » foreach
8,990,758 op/s » for of
1,713,807 op/s » map
Suites: 1
Benches: 4
Elapsed: 5,710.33 ms
结论
单凭循环 for
最可靠。
foreach
和 for ... of
差不多。
map
性能最低。
触发 react onchange 事件并赋值
var setValue = function (element, value) {
element.value = value;
if ('createEvent' in document) {
var event = new Event('input', {
bubbles: true });
element.dispatchEvent(event);
} else {
element.fireEvent('onchange');
}
};
Pipeline Operator (Proposal)
目前处于草稿阶段: https://github.com/tc39/proposal-pipeline-operator
function doubleSay(str) {
return `${
str}, ${
str}`;
}
function capitalize(str) {
return str[0].toUpperCase() + str.substring(1);
}
function exclaim(str) {
return `${
str}!`;
}
let result = 'hello' |> doubleSay |> capitalize |> exclaim;
result |> console.log;
//=> "Hello, hello!"
项目模板: https://github.com/willin/esnext-pipeline-biolerplate
Async (ES 7)
async function fn(args) {
// ...
}
// 等同于
function fn(args) {
return spawn(function* () {
// ...
});
}
多个await
命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
let foo = await getFoo();
let bar = await getBar();
上面代码中,getFoo
和getBar
是两个独立的异步操作(即互不依赖),被写成继发关系。这样比较耗时,因为只有getFoo
完成以后,才会执行getBar
,完全可以让它们同时触发。
// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
上面两种写法,getFoo
和getBar
都是同时触发,这样就会缩短程序的执行时间。
Proxy (ES 6)
经测试 Node v6.1.0 之后版本已集成。
示例代码:
const proxy = new Proxy(
{
},
{
get: (target, property) => [target, property]
}
);
console.log(proxy.func); // [ {}, 'func' ]
console.log(proxy.func('123')); // TypeError: proxy.func is not a function
const proxy = new Proxy(
{
},
{
get: (target, property) => (test) => [target, property, test]
}
);
console.log(proxy.func); // [Function]
console.log(proxy.func('123')); // [ {}, 'func', '123' ]
ES 6 作用域
以 For 循环为例:
var funcs = [];
for (var i = 0; i < 10; i += 1) {
funcs.push(function () {
console.log(i);
});
}
funcs.forEach((func) => func());
// 输出 10 十次
闭包:
var funcs = [];
for (var i = 0; i < 10; i += 1) {
funcs.push((function(value){
console.log(value); }(i));
}
funcs.forEach(func => func());
// 0 到 9 依次输出
在 ES6 中可以简化为:
const funcs = [];
for (let i = 0; i < 10; i += 1) {
funcs.push(() => console.log(i));
}
funcs.forEach((func) => func());
// 0 到 9 依次输出
Function 创建函数
var add = new Function('first', 'second = first', 'return first + second');
console.log(add(1, 1)); // 2
console.log(add(1)); // 2
var pickFirst = new Function('..args', 'return args[0]');
console.log(pickFirst(1, 2)); // 1
ES6 中互换值
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b); // 2 1
Fetch API AJAX
浏览器兼容性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3HRKmB2K-1690025164220)(/basic/js/fetch.png)]
支持检查
if (typeof fetch === 'function' && typeof window.fetch === 'function') {
// 支持
}
if (typeof fetch !== 'function' || typeof window.fetch !== 'function') {
// 不支持
}
示例代码
var req = new Request('/data.json', {
method: 'POST', cache: 'reload' });
fetch(req)
.then(function (res) {
return res.json();
})
.then(function (data) {
console.log(data);
});
跨域 Cookie 设置
credentials
凭证参数
fetch('a.com/api', {
credentials: 'include' }).then(function (res) {
// ...
});
或
var req = new Request('/data.json', {
method: 'POST', cache: 'reload', credentials: 'include' });
fetch(req)
.then(function (res) {
return res.json();
})
.then(function (data) {
console.log(data);
});