const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}];
// => [1, '1', 17, true, false, 'true', 'a', {}, {}]
const res1 = Array.from(new Set(arr));
const unique1 = arr => {
let len = arr.length;
for (let i = 0; i
const unique2 = arr => {
const res = [];
for (let i = 0; i
当然也能够用include、filter,思路大同小异。
const unique3 = arr => {
const res = [];
for (let i = 0; i
const unique4 = arr => {
return arr.filter((item, index) => {
return arr.indexOf(item) === index;
});
}
const unique5 = arr => {
const map = new Map();
const res = [];
for (let i = 0; i
该办法的参数是 Promise 实例数组, 而后其 then 注册的回调办法是数组中的某一个 Promise 的状态变为 fulfilled 的时候就执行. 因为 Promise 的状态只能扭转一次, 那么咱们只须要把 Promise.race 中产生的 Promise 对象的 resolve 办法, 注入到数组中的每一个 Promise 实例中的回调函数中即可.
Promise.race = function (args) {
return new Promise((resolve, reject) => {
for (let i = 0, len = args.length; i
apply 函数的实现步骤:
// apply 函数实现
Function.prototype.myApply = function(context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
let result = null;
// 判断 context 是否存在,如果未传入则为 window
cOntext= context || window;
// 将函数设为对象的办法
context.fn = this;
// 调用办法
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
// 将属性删除
delete context.fn;
return result;
};
Object.create()办法创立一个新对象,应用现有的对象来提供新创建的对象的__proto__。
// 模仿 Object.create
function create(proto) {
function F() {}
F.prototype = proto;
return new F();
}
// 模仿 instanceof
function instance_of(L, R) {
//L 示意左表达式,R 示意右表达式
var O = R.prototype; // 取 R 的显示原型
L = L.__proto__; // 取 L 的隐式原型
while (true) {
if (L === null) return false;
if (O === L)
// 这里重点:当 O 严格等于 L 时,返回 true
return true;
L = L.__proto__;
}
}
例: abbcccddddd -> 字符最多的是d,呈现了5次
let str = "abcabcabcbbccccc";
let num = 0;
let char = '';
// 使其依照肯定的秩序排列
str = str.split('').sort().join('');
// "aaabbbbbcccccccc"
// 定义正则表达式
let re = /(\w)\1+/g;
str.replace(re,($0,$1) => {
if(num <$0.length){
num = $0.length;
char = $1;
}
});
console.log(`字符最多的是${char},呈现了${num}次`);
(1)递归实现
一般的递归思路很容易了解,就是通过循环递归的形式,一项一项地去遍历,如果每一项还是一个数组,那么就持续往下遍历,利用递归程序的办法,来实现数组的每一项的连贯:
let arr = [1, [2, [3, 4, 5]]];
function flatten(arr) {
let result = [];
for(let i = 0; i
(2)reduce 函数迭代
从下面一般的递归函数中能够看出,其实就是对数组的每一项进行解决,那么其实也能够用reduce 来实现数组的拼接,从而简化第一种办法的代码,革新后的代码如下所示:
let arr = [1, [2, [3, 4]]];
function flatten(arr) {
return arr.reduce(function(prev, next){
return prev.concat(Array.isArray(next) ? flatten(next) : next)
}, [])
}
console.log(flatten(arr));// [1, 2, 3, 4,5]
(3)扩大运算符实现
这个办法的实现,采纳了扩大运算符和 some 的办法,两者独特应用,达到数组扁平化的目标:
let arr = [1, [2, [3, 4]]];
function flatten(arr) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
console.log(flatten(arr)); // [1, 2, 3, 4,5]
(4)split 和 toString
能够通过 split 和 toString 两个办法来独特实现数组扁平化,因为数组会默认带一个 toString 的办法,所以能够把数组间接转换成逗号分隔的字符串,而后再用 split 办法把字符串从新转换为数组,如上面的代码所示:
let arr = [1, [2, [3, 4]]];
function flatten(arr) {
return arr.toString().split(',');
}
console.log(flatten(arr)); // [1, 2, 3, 4,5]
通过这两个办法能够将多维数组间接转换成逗号连贯的字符串,而后再从新分隔成数组。
(5)ES6 中的 flat
咱们还能够间接调用 ES6 中的 flat 办法来实现数组扁平化。flat 办法的语法:arr.flat([depth])
其中 depth 是 flat 的参数,depth 是能够传递数组的开展深度(默认不填、数值是 1),即开展一层数组。如果层数不确定,参数能够传进 Infinity,代表不管多少层都要开展:
let arr = [1, [2, [3, 4]]];
function flatten(arr) {
return arr.flat(Infinity);
}
console.log(flatten(arr)); // [1, 2, 3, 4,5]
能够看出,一个嵌套了两层的数组,通过将 flat 办法的参数设置为 Infinity,达到了咱们预期的成果。其实同样也能够设置成 2,也能实现这样的成果。在编程过程中,如果数组的嵌套层数不确定,最好间接应用 Infinity,能够达到扁平化。 (6)正则和 JSON 办法 在第4种办法中曾经应用 toString 办法,其中依然采纳了将 JSON.stringify 的办法先转换为字符串,而后通过正则表达式过滤掉字符串中的数组的方括号,最初再利用 JSON.parse 把它转换成数组:
let arr = [1, [2, [3, [4, 5]]], 6];
function flatten(arr) {
let str = JSON.stringify(arr);
str = str.replace(/(\[|\])/g, '');
str = '[' + str + ']';
return JSON.parse(str);
}
console.log(flatten(arr)); // [1, 2, 3, 4,5]
函数防抖是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则从新计时。这能够应用在一些点击申请的事件上,防止因为用户的屡次点击向后端发送屡次申请。
// 函数防抖的实现
function debounce(fn, wait) {
let timer = null;
return function() {
let cOntext= this,
args = arguments;
// 如果此时存在定时器的话,则勾销之前的定时器从新记时
if (timer) {
clearTimeout(timer);
timer = null;
}
// 设置定时器,使事件间隔指定事件后执行
timer = setTimeout(() => {
fn.apply(context, args);
}, wait);
};
}
function getType(value) {
// 判断数据是 null 的状况
if (value === null) {
return value + "";
}
// 判断数据是援用类型的状况
if (typeof value === "object") {
let valueClass = Object.prototype.toString.call(value),
type = valueClass.split(" ")[1].split("");
type.pop();
return type.join("").toLowerCase();
} else {
// 判断数据是根本数据类型的状况和函数的状况
return typeof value;
}
}
apply原理与call很类似,不多赘述
// 模仿 apply
Function.prototype.myapply = function(context, arr) {
var cOntext= Object(context) || window;
context.fn = this;
var result;
if (!arr) {
result = context.fn();
} else {
var args = [];
for (var i = 0, len = arr.length; i
输出字符串s,以及其反复的次数,输入反复的后果,例如输出abc,2,输入abcabc。
function repeat(s, n) {
return (new Array(n + 1)).join(s);
}
递归:
function repeat(s, n) {
return (n > 0) ? s.concat(repeat(s, --n)) : "";
}
用一个滑动窗口装没有反复的字符,枚举字符记录最大值即可。用 map 保护字符的索引,遇到雷同的字符,把左边界挪动过来即可。移动的过程中记录最大长度:
var lengthOfLOngestSubstring= function (s) {
let map = new Map();
let i = -1
let res = 0
let n = s.length
for (let j = 0; j
函数柯里化概念: 柯里化(Currying)是把承受多个参数的函数转变为承受一个繁多参数的函数,并且返回承受余下的参数且返回后果的新函数的技术。
1)粗犷版
function add (a) {
return function (b) {
return function (c) {
return a + b + c;
}
}
}
console.log(add(1)(2)(3)); // 6
2)柯里化解决方案
var add = function (m) {
var temp = function (n) {
return add(m + n);
}
temp.toString = function () {
return m;
}
return temp;
};
console.log(add(3)(4)(5)); // 12
console.log(add(3)(6)(9)(25)); // 43
对于add(3)(4)(5),其执行过程如下:
function add (...args) {
//求和
return args.reduce((a, b) => a + b)
}
function currying (fn) {
let args = []
return function temp (...newArgs) {
if (newArgs.length) {
args = [
...args,
...newArgs
]
return temp
} else {
let val = fn.apply(this, args)
args = [] //保障再次调用时清空
return val
}
}
}
let addCurry = currying(add)
console.log(addCurry(1)(2)(3)(4, 5)()) //15
console.log(addCurry(1)(2)(3, 4, 5)()) //15
console.log(addCurry(1)(2, 3, 4, 5)()) //15
call 函数的实现步骤:
// call函数实现
Function.prototype.myCall = function(context) {
// 判断调用对象
if (typeof this !== "function") {
console.error("type error");
}
// 获取参数
let args = [...arguments].slice(1),
result = null;
// 判断 context 是否传入,如果未传入则设置为 window
cOntext= context || window;
// 将调用函数设为对象的办法
context.fn = this;
// 调用函数
result = context.fn(...args);
// 将属性删除
delete context.fn;
return result;
};
次要的实现思路就是:
var arr = [1,2,3,4,5,6,7,8,9,10];
for (var i = 0; i
还有一办法就是倒序遍历:
var arr = [1,2,3,4,5,6,7,8,9,10];
let length = arr.length,
randomIndex,
temp;
while (length) {
randomIndex = Math.floor(Math.random() * length--);
temp = arr[length];
arr[length] = arr[randomIndex];
arr[randomIndex] = temp;
}
console.log(arr)
类数组是具备length属性,但不具备数组原型上的办法。常见的类数组有arguments、DOM操作方法返回的后果。
Array.from(document.querySelectorAll('div'))
Array.prototype.slice.call(document.querySelectorAll('div'))
[...document.querySelectorAll('div')]
Array.prototype.concat.apply([], document.querySelectorAll('div'));
Array.prototype.filter = function(callback, thisArg) {
if (this == undefined) {
throw new TypeError('this is null or not undefined');
}
if (typeof callback !== 'function') {
throw new TypeError(callback + 'is not a function');
}
const res = [];
// 让O成为回调函数的对象传递(强制转换对象)
const O = Object(this);
// >>>0 保障len为number,且为正整数
const len = O.length >>> 0;
for (let i = 0; i
对于>>>0
有疑难的:解释>>>0的作用
// 应用闭包实现
for (var i = 0; i <5; i++) {
(function(i) {
setTimeout(function() {
console.log(i);
}, i * 1000);
})(i);
}
// 应用 let 块级作用域
for (let i = 0; i <5; i++) {
setTimeout(function() {
console.log(i);
}, i * 1000);
}
// promise 封装实现:
function getJSON(url) {
// 创立一个 promise 对象
let promise = new Promise(function(resolve, reject) {
let xhr = new XMLHttpRequest();
// 新建一个 http 申请
xhr.open("GET", url, true);
// 设置状态的监听函数
xhr.Onreadystatechange= function() {
if (this.readyState !== 4) return;
// 当申请胜利或失败时,扭转 promise 的状态
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
// 设置谬误监听函数
xhr.Onerror= function() {
reject(new Error(this.statusText));
};
// 设置响应的数据类型
xhr.respOnseType= "json";
// 设置申请头信息
xhr.setRequestHeader("Accept", "application/json");
// 发送 http 申请
xhr.send(null);
});
return promise;
}