JS 编程题
阿里面试题(变量赋值)
let a = {n: 1,};
let b = a;
a.x = a = {n: 2,};
console.log(a.x); // undefined
console.log(b); // {n: 1, x: {n: 2}}
let a = 12,
b = 12;
function fn() {// console.log(a, b); // Uncaught ReferenceError: Cannot access 'a' before initialization at fn
console.log(b); // 12
let a = (b = 13);
console.log(a, b); // 13 13
}
fn();
console.log(a, b); // 12 13
let i = 1;
let fn = (i) => (n) => console.log(n + ++i);
let f = fn(1);
f(2); // 4
fn(3)(4); // 8
f(5); // 8
console.log(i); // 1
var n = 0;
function a() {
var n = 10;
function b() {
n++;
console.log(n);
}
b();
return b;
}
var c = a();
c();
console.log(n);
// 11 12 0
参考 js 间断赋值的问题
美团面试题
var obj = {
2: 3,
3: 4,
length: 2,
push: Array.prototype.push,
};
obj.push(1);
obj.push(2);
console.log(obj);
// {2: 1, 3: 2, length: 4, push: ƒ} 解析:因为对象的 length 为 2, 所以 push 1 2 会笼罩 2 3 的值
// 比照
var obj = {
length: 2,
push: Array.prototype.push,
};
obj.push(1);
obj.push(2);
obj.push(3);
console.log(obj);
// {2: 1, 3: 2, 4: 3, length: 5, push: ƒ}
阿里经典面试题(考查变量晋升 / 静态方法 / 实例办法 / 原型办法调用)
function Foo() {getName = function () {console.log(1);
};
return this;
}
Foo.getName = function () {console.log(2);
};
Foo.prototype.getName = function () {console.log(3);
};
var getName = function () {console.log(4);
};
function getName() {console.log(5);
}
Foo.getName(); // 2 解析:调用函数的静态方法
getName(); // 4 解析:函数表达式会笼罩函数申明式办法
Foo().getName(); // 1 解析:调用函数本身的办法
getName(); // 1 解析: 受前一行代码执行影响相当于调用 this.getName(), 其中 this 指向 window,因为 Foo 办法外面定义 getName 的时候没有申明, 所以变成了全局变量
new Foo.getName(); // 2 解析:相当于执行 new (Foo.getName)()
new Foo().getName(); // 3 解析:调用函数的实例办法, 相当于执行(new Foo()).getName()
new new Foo().getName(); // 3 解析:相当于执行 new (new Foo()).getName)()
// 操作运算符的优先级: () > new > .
字节面试题(递归 / 微工作 / 宏工作)
function fn() {fn();
}
fn(); // Uncaught RangeError: Maximum call stack size exceeded
var num = 0;
function fn() {console.log(num++);
setTimeout(fn, 1000);
}
fn(); // 能够失常执行,为什么?// 解析:起因是因为 setTImeout 属于异步宏工作,不在主线程栈内存中
字节编程题
const list = [1, 2, 3];
const square = (num) => {return new Promise((resolve, reject) => {setTimeout(() => {resolve(num * num);
}, 1000);
});
};
function test() {list.forEach(async (x) => {const res = await square(x);
console.log(res);
});
}
test();
// 执行后果:1s 之后输入 1 4 9
// 不能批改 square 办法,实现每隔一秒输入后果
const list = [1, 2, 3];
const square = (num) => {return new Promise((resolve, reject) => {setTimeout(() => {resolve(num * num);
}, 1000);
});
};
function test() {list.forEach((x, index) => {setTimeout(async () => {const res = await square(x);
console.log(res);
}, index * 1000);
});
}
test();
笔者自出的立刻执行函数赋值编程题
var a = 111;
(function a() {console.log(a);
a = 222;
console.log(a);
})();
console.log(a);
// 输入后果:// ƒ a() {// console.log(a);
// a = 222;
// console.log(a);
// }
// ƒ a() {// console.log(a);
// a = 222;
// console.log(a);
// }
// 111
var c = 111;
(function c(c) {console.log(c);
c = 123;
console.log(c);
})(c);
console.log(c);
// 输入后果:// 111
// 123
// 111
快手面试编程题
实现 add(1)(2)(3)(4)(5).sum()和 add(1)(2, 3)(4)(5).sum()参数不定的累加成果
let add = (...args) => {let foo = (...newArgs) => {return add(...args, ...newArgs);
};
foo.toString = () => {return args.reduce((a, b) => a + b);
};
foo.sum = () => {return foo.toString();
};
return foo;
};
// 测试后果:console.log(add(1)(2)(3)(4)(5).sum()); // 15
console.log(add(1)(2, 3)(4)(5).sum()); // 15
// 优化版代码
let add = (...args) => {let foo = (...newArgs) => {return add(...args, ...newArgs);
};
foo.sum = () => {return args.reduce((a, b) => a + b);
};
return foo;
};
// 测试后果:console.log(add(1)(2)(3)(4)(5).sum()); // 15
console.log(add(1)(2, 3)(4)(5).sum()); // 15
求字符串 '(1+2)*3’ 运算后果(携程面试题)
办法一:应用 eval
办法
// 非严格模式下
let str = '(1+2)*3';
let result = eval(str);
console.log(result);
// 严格模式下报错:Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src'strict-dynamic'
办法二:应用 new Funciton
办法
// 非严格模式下
let str = '(1+2)*3';
function strCalc(str) {return new Function(`return ${str}`)();}
let result = strCalc(str);
console.log(result);
// 严格模式下报错:Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src'strict-dynamic'
办法三:利用 script
标签内容为可执行代码
let str = '(1+2)*3';
function strCalc(str) {let myScript = document.createElement('script');
myScript.innerHTML = `window.golal_calc_result=${str}`; // 把执行后果保留到全局对象
document.body.appendChild(myScript);
document.body.removeChild(myScript);
}
strCalc(str);
console.log(window.golal_calc_result);
考查 JS 事件循环微工作和宏工作
console.log(1);
setTimeout(function () {console.log(2);
}, 0);
var promise = new Promise(function (resolve, reject) {console.log(3);
setTimeout(function () {console.log(4);
resolve();}, 1000);
});
promise.then(function () {console.log(5);
setTimeout(function () {console.log(6);
}, 0);
});
console.log(7);
// 输入后果程序:1 3 7 2 4 5 6
// 解析:JS 代码执行优先级:主线程 -> 微工作 -> 宏工作
var promise = new Promise(function (resolve, reject) {setTimeout(function () {console.log(1);
resolve();}, 3000);
});
promise
.then(function () {setTimeout(function () {console.log(2);
}, 2000);
})
.then(function () {setTimeout(function () {console.log(3);
}, 1000);
})
.then(function () {setTimeout(function () {console.log(4);
}, 0);
});
// 输入后果:3s 后输入 1 和 4,再过 1s 输入 3,再过 1s 输入 2
// 解析:promise.then()办法要等 resolve()执行当前,才会执行前面的 then 办法,前面的这些办法按定时器异步流程解决
理解更多
async/await 和 setTimeout 以及 promise(字节面试题)
async function async1() {console.log("async1 start");
await async2();
console.log(`async1 end`);
}
async function async2() {console.log("async2");
}
console.log("script start");
setTimeout(() => {console.log("setTimeout");
}, 0);
async1();
new Promise((resolve, reject) => {console.log("promise1");
resolve();}).then(() => {console.log("promise2");
});
console.log("script end");
// 输入后果:// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout
promise 串行问题(腾讯文档)
let promiseArr = [() => {
return new Promise(res => {console.log('run 1', Date.now());
res('run 1 resolve');
});
},
() => {
return new Promise(res => {console.log('run 2', Date.now());
res('run 2 resolve');
});
},
() => {
return new Promise(res => {console.log('run 3', Date.now());
res('run 3 resolve');
});
},
]
async function fn () {for (let i = 0; i < promiseArr.length; i++) {
// 串行打印 console.log;
// await promiseArr[i]();
// 串行打印 console.log 并执行 resolve
await promiseArr[i]().then((value) => {console.log(value);
});
}
}
fn();
事件循环(字节面试题)
function test () {console.log(1);
Promise.resolve().then(test);
}
test();
setTimeout(() => {console.log(2)}, 0)
// 打印后果:// 始终输入 1 不会执行 setTimeout 外面的回调函数
promise、async/await
async function fn() {let data = await (() => 4)();
console.log(data);
}
console.log(1);
new Promise(resolve => resolve(console.log(2))).then(data => console.log(data));
console.log(3);
fn();
// 打印后果:// 1
// 2
// 3
// undefined
// 4
// Promise {<fulfilled>: undefined}
// 字节面试题
new Promise((reslove, reject) => {reject();
}).then(null, () => {console.log(1);
}).then(() => {console.log(2);
}).then(() => {console.log(3);
});
// 打印后果:1 2 3
new Promise((reslove, reject) => {reject();
}).then(null, () => {console.log(1);
}).then(() => {new Promise((reslove, reject) => {reject();
}).then(null, () => {console.log('a');
}).then(() => {console.log('b');
}).then(() => {console.log('c');
})
}).then(() => {console.log(3);
})
// 打印后果:// 1
// a
// 3
// b
// c
new Promise((resolve, reject) => {resolve();
}).then(null, () => {console.log(1);
}).then(() => {new Promise((resolve, reject) => {console.log(2);
resolve();}).then(null, () => {console.log('a');
}).then(() => {console.log('b');
}).then(() => {console.log('c');
})
}).then(() => {console.log(3);
})
// 打印后果:// 2
// 3
// b
// c
new Promise((resolve, reject) => {reject();
}).then(null, () => {console.log(1);
}).then(() => {new Promise((resolve, reject) => {console.log(2);
reject();}).then(null, () => {console.log('a');
}).then(() => {console.log('b');
}).then(() => {console.log('c');
})
}).then(() => {console.log(3);
})
// 1
// 2
// a
// 3
// b
// c
腾讯视频编程题
function foo () {
var a = 0;
return function () {console.log(a++);
}
}
var f1 = foo(),
f2 = foo();
f1(); // 0
f1(); // 1
f2(); // 0
function Page() {console.log(this);
return this.hosts;
}
Page.hosts = ['h1'];
Page.prototype.hosts = ['h2'];
var p1 = new Page();
var p2 = Page();
console.log(p1.hosts); // undefined
console.log(p2.hosts); // Uncaught TypeError: Cannot read property 'hosts' of undefined
如果让一个不可迭代对象,变成可迭代
var obj = {
0: 0,
1: 1,
length: 2,
};
for (i of obj) {console.log(i);
}
// 报错:Uncaught TypeError: obj is not iterable
var obj = {
0: 0,
1: 1,
length: 2,
[Symbol.iterator]: Array.prototype[Symbol.iterator],
};
for (i of obj) {console.log(i);
}
// 原理:可迭代对象都领有 @@iterator 属性
实现深拷贝
罕用的简略实现形式:类型判断 + 递归
function deepClone(obj) {var newObj = obj instanceof Array ? [] : {};
for (var i in obj) {newObj[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i];
}
return newObj;
}
// test
var obj = {
number: 1,
string: "abc",
bool: true,
undefined: undefined,
null: null,
symbol: Symbol("s"),
arr: [1, 2, 3],
date: new Date(),
userInfo: {
name: "Better",
position: "front-end engineer",
skill: ["React", "Vue", "Angular", "Nodejs", "mini programs"],
},
func: function () {console.log("hello better");
},
};
console.log(deepClone(obj));
从打印的后果来看,这种实现形式还存在很多问题:这种形式只能实现特定的 object 的深度复制(比方对象、数组和函数),不能实现 null 以及包装对象 Number,String,Boolean,以及 Date 对象,RegExp 对象的复制。
一行代码实现形式:联合应用 JSON.stringify()
和JSON.parse()
var obj = {
number: 1,
string: "abc",
bool: true,
undefined: undefined,
null: null,
symbol: Symbol("s"),
arr: [1, 2, 3],
date: new Date(),
userInfo: {
name: "Better",
position: "front-end engineer",
skill: ["React", "Vue", "Angular", "Nodejs", "mini programs"],
},
func: function () {console.log("hello better");
},
};
var copyObj = JSON.parse(JSON.stringify(obj));
console.log(copyObj);
从打印后果能够得出以下论断:
undefined
、symbol
、function
类型间接被过滤掉了date
类型被主动转成了字符串类型
实现一个 bind 函数
原理:应用 apply()
或者 call()
办法
初始版本
Function.prototype.customBind = function (context) {
var self = this; // 保留函数的上下文
var args = [].slice.call(arguments, 1); // 获取自定义 bind 函数的参数
return function () {args = args.concat([].slice.call(arguments)); // 获取自定义 bind 函数返回函数传入的参数
return self.apply(context, args);
};
};
var obj = {
name: "Better",
position: "front-end engineer",
};
var func = function (age) {console.log("name", this.name);
console.log("position", this.position);
console.log("age", age);
};
var f = func.customBind(obj, 18);
f();
思考到原型链(最终版)
Function.prototype.customBind = function (context) {
// 必须在函数上应用,否则抛出谬误
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
var self = this; // 保留函数的上下文
var args = Array.prototype.slice.call(arguments, 1); // 获取自定义 bind 函数的参数
var fNOP = function () {};
var fBound = function () {var bindArgs = Array.prototype.slice.call(arguments); // 获取自定义 bind 函数返回函数传入的参数
return self.apply(
this instanceof fNOP ? this : context,
args.concat(bindArgs)
);
};
// 这里应用寄生组合继承
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
// 测试
var obj = {
name: "Better",
position: "front-end engineer",
};
var func = function (age) {console.log("name", this.name);
console.log("position", this.position);
console.log("age", age);
};
var f = func.customBind(obj, 18);
f();
点击理解更多
性能优化之防抖和节流
对于频繁触发的事件,比方,scroll
、keyup
、mouseover
、resize
等事件,如果不做一些非凡解决的话,可能会影响性能,甚至造成页面卡顿。
防抖和节流就能很好的解决这类问题。
防抖
定义:在规定工夫内,屡次触发事件后,事件处理函数只执行一次,并且是在触发操作完结后执行。
原理:对处理函数进行延时操作,若设定的延时到来之前,再次触发事件,则革除上一次的延时操作定时器,从新定时。
function debounce(fn, wait) {
var timeId = null;
return function () {
var context = this; // 保留绑定事件的对象,如 document
var args = arguments; // 获取事件参数,如 event
timeId && clearTimeout(timeId); // 如果规定工夫内(wait)再次触发事件,则革除定时器
timeId = setTimeout(function () {fn.apply(context, args); // 应用 apply 办法把 fn 函数的 this 指向事件对象
}, wait);
};
}
// 测试
function func() {console.log(111);
}
document.addEventListener("mouseover", debounce(func, 1000));
如果心愿立刻执行一次,而后等到进行触发 n 秒后,才能够从新触发执行。
function debounce(fn, wait, immediately) {
var timeId = null;
return function () {
var context = this;
var args = arguments;
timeId && clearTimeout(timeId);
if (immediately) {
// 如果曾经执行过,则不再执行
var canExecute = !timeId;
timeId = setTimeout(function () {timeId = null;}, wait);
if (canExecute) {fn.apply(context, args);
}
} else {timeId = setTimeout(function () {fn.apply(context, args); // 应用 apply 办法把 fn 函数的 this 指向事件对象
}, wait);
}
};
}
// 测试
function func() {console.log(111);
}
document.addEventListener("mouseover", debounce(func, 1000, true));
// document.addEventListener('mouseover', debounce(func, 1000));
点击理解更多
节流
定义:触发函数事件后,规定工夫距离内无奈间断调用,只有上一次函数执行后,过了规定的工夫距离,能力进行下一次的函数调用。
原理:如果你继续触发事件,每隔一段时间,只执行一次事件。
对于节流的实现,有两种支流的实现形式,一种是应用工夫戳,一种是设置定时器。
应用工夫戳,当触发事件的时候,咱们取出以后的工夫戳,而后减去之前的工夫戳(最一开始值设为 0),如果大于设置的工夫周期,就执行函数,而后更新工夫戳为以后的工夫戳,如果小于,就不执行。
// 应用工夫戳
function throttle(fn, wait) {
var prev = 0;
return function () {
var context = this;
var args = arguments;
var now = new Date().getTime();
// if (!prev) prev = now;
if (now - prev > wait) {
// 如果工夫距离大于 wait,执行函数
fn.apply(context, args);
prev = now; // 把以后工夫赋值给前一个工夫
}
};
}
// 测试
function func() {console.log(111);
}
document.addEventListener("mouseover", throttle(func, 1000));
应用定时器:当触发事件的时候,咱们设置一个定时器,再触发事件的时候,如果定时器存在,就不执行,直到定时器执行,而后执行函数,清空定时器,这样就能够设置下个定时器。
// 应用定时器
function throttle(fn, wait) {
var timeId = null;
return function () {
var context = this;
var args = arguments;
if (!timeId) {
// 如果没有定时器
timeId = setTimeout(function () {fn.apply(context, args);
timeId = null;
}, wait);
}
};
}
// 测试
function func() {console.log(111);
}
document.addEventListener("mouseover", throttle(func, 1000));
总结:
- 第一种事件会立即执行,第二种事件会在 n 秒后第一次执行
- 第一种事件进行触发后没有方法再执行事件,第二种事件进行触发后仍然会再执行一次事件
点击理解更多
应用 setTimeout 实现 setInterval 性能
咱们平时开发中尽量避免应用 setInterval 反复定时器,这种反复定时器的规定有两个问题:
- 某些距离会被跳过
- 多个定时器的代码执行工夫可能会比预期小
var i = 0;
function count() {console.log(i++);
setTimeout(count, 1000);
}
setTimeout(count, 1000);
或者应用 arguments.callee
var i = 0;
setTimeout(function () {
// do something
console.log(i++);
setTimeout(arguments.callee, 1000);
}, 1000);
如何实现 sleep 成果
办法一:应用 promise
function sleep(time) {return new Promise(function (resolve, reject) {console.log("start");
setTimeout(function () {resolve();
}, time);
});
}
sleep(1000).then(function () {console.log("end");
});
// 先输入 start,提早 1000ms 后输入 end
办法二:应用 async/await
function sleep(time) {return new Promise(function (resolve, reject) {setTimeout(function () {
// do something
resolve();}, time);
});
}
async function test() {console.log("start");
var result = await sleep(1000);
console.log("end");
return result;
}
test(); // 先输入 start,提早 1000ms 后输入 end
办法三:应用 generate
function* sleep(time) {yield new Promise((resolve, reject) => {console.log("start");
setTimeout(() => {
// do something
resolve();}, time);
});
}
sleep(1000)
.next()
.value.then(() => {console.log("end");
}); // 先输入 start,提早 1000ms 后输入 end
如何实现 a == 1 && a == 2 && a == 3 为 true
办法一:联合应用数组的 toString()
和shift()
办法
var a = [1, 2, 3];
// a.join = a.shift;
// a.valueOf = a.shift;
a.toString = a.shift;
console.log(a == 1 && a == 2 && a == 3); // true
原理:当简单类型数据与根本类型数据作比拟时会产生隐性转换,会调用 toString()
或者 valueOf()
办法
办法二:原理和办法一一样都是批改 toString()
办法
var a = {
value: 1,
toString: function () {return a.value++;},
};
console.log(a == 1 && a == 2 && a == 3); // true
实现 add(1)(2)(3)这类办法以及扩大办法
// 一般写法
var add = function (a) {return function (b) {return function (c) {return a + b + c;};
};
};
console.log(add(1)(2)(3)); // 6
// 扩大写法
function addExtend(x) {
var sum = x;
var temp = function (y) {
sum = sum + y;
return temp;
};
temp.toString = function () {return sum;};
return temp;
}
console.log(addExtend(1)(2)(3)); // ƒ 6
console.log(typeof addExtend(1)(2)(3)); // function
console.log(Number(addExtend(1)(2)(3))); // 6
console.log(Number(addExtend(1)(2)(3)(4)(5))); // 15
闭包和工作队列例子
for (var i = 0; i < 5; i++) {
setTimeout((function (i) {console.log(i);
})(i),
i * 1000
);
}
// 测试后果:立刻输入 0 1 2 3 4
for (var i = 0; i < 5; i++) {setTimeout(function () {console.log(i);
}, i * 1000);
}
// 测试后果:立刻输入 5 而后每隔一秒输入 5 总共输入 5 次
for (let i = 0; i < 5; i++) {setTimeout(function () {console.log(i);
}, i * 1000);
}
// 测试后果:立刻输入 0 而后每隔一秒别离输入 1 2 3 4
应用正则表达式匹配 url 参数键值对(兼容 url 中蕴含多个? 和 #号)
let reg = /([^?&#]+=[^?&#]+)/g;
let str =
"https://c2b.brightoilonline.com/bdh5/channel.html?chelun_params=ad0bb3e5fc3b3bfeb9b53cc9686eb1aaaecb8a53e9f4a77c5ed68714123b25913219200cba48d9044c7b48325436960f42c1cde18f349ef63ab53ee791970243a8ba79f9a2dc8aa1#/chelunGasList?pcode=c2b8g717rkj603o15005&fromApp=true";
console.log(str.match(reg));
// 测试后果:["chelun_params=ad0bb3e5fc3b3bfeb9b53cc9686eb1aaaecb…f42c1cde18f349ef63ab53ee791970243a8ba79f9a2dc8aa1", "pcode=c2b8g717rkj603o15005", "fromApp=true"]
str =
"https://c2b-test2.brightoilonline.com/bdh5/channel.html#/chelungaslist?pcode=c2b0293jm44x97an6339&fromApp=true";
console.log(str.match(reg));
// 测试后果:["pcode=c2b0293jm44x97an6339", "fromApp=true"]
str =
"https://c2b-test2.brightoilonline.com/bdh5/channel.html?pcode=c2b0293jm44x97an6339&fromApp=true";
console.log(str.match(reg));
// 测试后果:["pcode=c2b0293jm44x97an6339", "fromApp=true"]
解析 URL Params 为对象
let url =
"http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled";
parseParam(url);
/* 后果
{ user: 'anonymous',
id: [123, 456], // 反复呈现的 key 要组装成数组,能被转成数字的就转成数字类型
city: '北京', // 中文需解码
enabled: true, // 未指定值得 key 约定为 true
}
*/
function parseParam(url) {const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 前面的字符串取出来
const paramsArr = paramsStr.split("&"); // 将字符串以 & 宰割后存到数组中
let paramsObj = {};
// 将 params 存到对象中
paramsArr.forEach((param) => {if (/=/.test(param)) {
// 解决有 value 的参数
let [key, val] = param.split("="); // 宰割 key 和 value
val = decodeURIComponent(val); // 解码
val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字
if (paramsObj.hasOwnProperty(key)) {
// 如果对象有 key,则增加一个值
paramsObj[key] = [].concat(paramsObj[key], val);
} else {
// 如果对象没有这个 key,创立 key 并设置值
paramsObj[key] = val;
}
} else {
// 解决没有 value 的参数
paramsObj[param] = true;
}
});
return paramsObj;
}
// 进阶:应用原生 URLSearchParams 对象
function optParseQuery(url) {const u = new URL(url)
const sp = new URLSearchParams(u.search)
return sp.entries()}
console.log(optParseQuery(url))
// {
// "user": "anonymous",
// "id": "456",
// "city": "北京",
// "enabled": ""
// }
数组对象去重
/**
* @param {Array} arr 去重的数组对象
* @param {String} key 依据 key 进行去重
* @return {Array} 去重后的数组对象
*/
// 办法一
function uniqueArrObjByKey (arr, key) {const map = Object.create(null)
const res = []
arr.forEach(item => {if (!map[item[key]]) {map[item[key]] = true
res.push(item)
}
})
return res
}
// 办法二
function uniqueArrObjByKey (arr, key) {const map = Object.create(null)
const res = arr.reduce((cur, next) => {map[next[key]] ? '' : map[next[key]] = true && cur.push(next)
return cur
}, []) // 设置 cur 默认类型为数组,并且初始值为空的数组
return res
}
// 测试
var arr = [{name: '廖小新', age: 18}, {name: '廖小物', age: 18}, {name: '廖小新', age: 20}, {name: '廖小物', age: 18}, {name: '廖小念', age: 18}]
console.log(uniqueArrObjByKey(arr, 'name'))
console.log(uniqueArrObjByKey(arr, 'age'))
给定两个数组,编写一个函数来计算它们的交加
阐明:
- 输入后果中的每个元素肯定是惟一的。
- 咱们能够不思考输入后果的程序。
// 办法一:应用 filter 和 set 办法
function findIntersection(arr1, arr2) {return [...new Set(arr1.filter((item) => arr2.includes(item)))];
}
var arr1 = [1, 2, 2, 3];
var arr2 = [2, 3, 3, 4];
findIntersection(arr1, arr2); // [2, 3]
// 办法二:应用 map 哈希表
function findIntersection(arr1, arr2) {var res = new Set();
var set1 = new Set(arr1);
var set2 = new Set(arr2);
for (let item of set2) {if (set1.has(item)) {res.add(item);
}
}
return [...res];
}
var arr1 = [1, 2, 2, 3];
var arr2 = [2, 3, 3, 4];
findIntersection(arr1, arr2); // [2, 3]
function findIntersection(arr1, arr2) {var map = {};
var res = [];
arr1.forEach((item) => {map[item] = true;
});
arr2.forEach((item) => {if (map[item]) {res.push(item);
}
});
res = [...new Set(res)];
return res;
}
var arr1 = [1, 2, 2, 3];
var arr2 = [2, 3, 3, 4];
findIntersection(arr1, arr2); // [2, 3]
// 扩大求三个数组的交加
function findThreeIntersection(arr1, arr2, arr3) {const map1 = new Set(arr1);
const map2 = new Set(arr2);
const map3 = new Set(arr3);
const res = [];
arr1.forEach((item) => {if (map2.has(item) && map3.has(item)) {res.push(item);
}
});
return [...new Set(res)];
}
var arr1 = [1, 2, 2, 3, 5];
var arr2 = [2, 3, 3, 4, 3, 5];
var arr3 = [1, 2, 3, 3, 4, 5];
findThreeIntersection(arr1, arr2, arr3); // [2, 3]
更多汇合操作参考 Set
es6 尾调用 - 尾递归
求正整数 n 的阶乘
function factorial (n) {if (n === 1) return 1
return n * factorial(n - 1)
}
console.time()
factorial(1000)
console.timeEnd()
// default: 1.697998046875 ms
// 应用尾递归
function factorial (n, total) {if (n === 1) return total
return factorial(n - 1, n * total)
}
console.time()
factorial(1000, 1)
console.timeEnd()
es6 尾调用 - 尾递归
本文由 mdnice 多平台公布