1
let i;
for (i = 0; i < 3; i++) {
let log = () => {
console.log(i);
};
setTimeout(log, 0);
}
function demo() {
let x = (b = 0);
return x;
}
demo();
console.log(typeof x);
console.log(typeof b);
解析
- demo(),可以看到用 let 定义了 x,之后将 x return 出去;b 未定义,直接赋值的,那么就默认在 window 下。
- typeof x, 并未定义 x,所以是 undefined
- typeof b, b 是 0,所以是 number.
- 同步都执行完了,那就开始执行异步。由于 i 是没有在 for 循环块级作用域里面定义,拿到的始终跟最后一次的值。
2.
let sender = { a: 1, c: undefined };
function demo1() {
with (sender) {
a = 2;
b = 3;
c = 4;
}
}
demo1();
console.log(sender);
function demo2(str) {
eval(str);
console.log(x);
}
var x = 1;
demo2('var x = 3');
console.log(x);
解析
- with 作用域,只会赋值当前已有属性的值
- 执行 demo2,eval 执行,此时 x 是 3。
3.
var a = {};
var b = { key: 'b' };
var c = { key: 'c' };
var d = [3, 5, 6];
a[b] = 123;
a[c] = 345;
a[d] = 333;
console.log(a[b]);
console.log(a[c]);
console.log(a[d]);
4.
new Promise(res => {
setTimeout(() => {
console.log(0);
}, 0);
res();
}).then(() => {
setTimeout(() => {
console.log(1);
}, 0);
});
setTimeout(() => {
console.log(2);
}, 0);
new Promise(res => setTimeout(res, 0)).then(() => {
console.log(3);
setTimeout(() => {
console.log(4);
}, 0);
new Promise(r => r()).then(() => console.log(5));
});
setTimeout(() => {
console.log(6);
}, 0);
new Promise(res => res()).then(() => {
console.log(7);
});
for (var i = 8; i < 11; i++) {
setTimeout(() => {
console.log(i);
}, 0);
console.log(i);
}
解析
慢慢思考,沉下心做。
- 先同步再异步, 先微任务再宏任务。队列要分清除。
new Promise(xxx) 是同步,then() 是微任务,setTimeout 是宏任务。
5.
function Foo() {
getName = function() {
console.log(1);
};
return this;
}
getName();
Foo.getName = function() {
console.log(2);
};
Foo.prototype.getName = function() {
console.log(3);
};
var getName = function() {
console.log(4);
};
function getName() {
console.log(5);
}
biz();
function biz() {
console.log(8);
}
if ([] == false) {
function biz() {
console.log(6);
}
} else {
function biz() {
console.log(7);
}
}
biz();
Foo.getName();
getName();
Foo().getName();
getName();
Foo.getName();
new Foo().getName();
解析
先定义后执行!
6. 三数之和,请挑选出数组中三个随机整数和位 100 的所有数据
function threeSum(arr) {
const len = arr.length;
let result = [];
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
for (let k = j + 1; k < len; k++) {
if (arr[i] + arr[j] + arr[k] === 100) {
result.push([arr[i], arr[j], arr[k]]);
}
}
}
}
return result;
}
threeSum([20, 30, 60, -10, 50, 15, 25]);
// [ [ 20, 30, 50 ], [ 60, -10, 50 ], [ 60, 15, 25 ] ]
7. 请用数组方法和 Math.random() 在一条语句的情况下实现生成给定位数的随机数组。
例如生成 10 位随机数组[96, 64, 70, 30, 43, 38, 39, 77, 80, 35], 数组内的数字随机生成。
new Array(10).fill(0).map(item => Math.random() * 100);
Array.from(new Array(10)).map(item => Math.random() * 100);
Array.from({ length: 10 }, () => Math.random() * 10);
8. 实现一个 bind 方法
Function.prototype.bind = function() {
let thatFunc = this,
thatArgs = arguments[0];
let slice = Array.prototype.slice;
let args = slice.call(arguments, 1);
return function() {
let _args = args.concat(slice.call(arguments));
return thatFunc.apply(thatArgs, _args);
};
};
9. 实现一个 setter 方法
例如
let setter = function(content, key, value) {
// todo
};
let n = {
a: {
b: {
c: {
d: 1,
bx: {
y: 1
}
}
}
}
};
setter(n, 'a.b.c.d', 3);
console.log(n.a.b.c.d); // 3
setter(n, 'a.b.c.bx', 1);
console.log(n.a.b.c.bx); // 1
let setter = function(content, key, value) {
let path = key.split('.');
for (let i = 0; i < path.length; i++) {
const k = path[i];
if (i === path.length - 1) {
content[k] = value;
break;
}
content = content[k];
}
};
10. 对象解构赋值
var obj1 = { name: 'xiaoming', age: 8, weight: '60kg' };
var obj2 = { account: 'admin', password: 'admin' };
var obj3 = { remember: true };
合并 obj1, obj2, obj3, 使用新变量 obj4 保存
let obj4 = { ...obj1, ...obj2, ...obj3 };
// 或者
let obj4 = Object.assign({}, obj1, obj2, obj3);
获取除了 name 和 account 的属性
function getOtherProps(object, keys) {
return Object.keys(object).reduce((obj, key) => {
if (keys.includes(key)) return obj;
obj[key] = object[key];
return obj;
}, {});
}
getOtherProps(obj4, ['name', 'key']);
11. 实现一个方法可以对数组对象内的 name 去重
var list = [
{ id: 1, name: 'xiaomin' },
{ id: 2, name: 'liudehua' },
{ id: 3, name: 'guofucheng' },
{ id: 4, name: 'zhangxueyou' },
{ id: 5, name: 'liming' },
{ id: 6, name: 'xiaomin' }
];
function checkDuplicate(list) {
let result = [],
keys = [];
for (const item of list) {
if (!keys.includes(item.name)) {
keys.push(item.name);
result.push(item);
}
}
return result;
}
function checkDuplicate(list) {
let _obj = {};
return list.reduce((obj, item, index, arr) => {
if (!_obj[item.name]) {
obj.push(item);
_obj[item.name] = true;
}
return obj;
}, []);
}
checkDuplicate(list);
12. 实现以下需求
var arr = [
{ id: 1, pid: 0, title: '首页' },
{ id: 2, pid: 1, title: '订单列表' },
{ id: 3, pid: 1, title: '刊登管理' },
{ id: 4, pid: 3, title: '刊登列表' },
{ id: 5, pid: 3, title: '刊登设置' },
{ id: 6, pid: 0, title: '登录' }
];
// 测试
function deep(list, id) {
if (!Array.isArray(list)) return list;
for (const item of list) {
if (item.id === id) return item;
if (Array.isArray(item.children)) {
return deep(item.children, id);
}
}
return null;
}
var newArr = arr.slice();
newArr.sort((a, b) => a.pid - b.pid);
let obj = newArr.reduce((arr, item) => {
if (item.pid === 0) {
arr.push(item);
return arr;
}
const pNdoe = deep(arr, item.pid);
if (!pNdoe.children) pNdoe.children = [];
pNdoe.children.push(item);
return arr;
}, []);
console.log(obj);
13. 实现 calculate
calculate(2)(3)('+'); // 5
calculate(2)(3)('*'); // 6
function calculate() {
const slice = Array.prototype.slice;
let args = slice.call(arguments);
const temp = function() {
let argsAll = args.concat(slice.call(arguments));
if (argsAll.length < 3) {
return calculate.apply(null, argsAll);
}
const idx = argsAll.length - 1;
const sign = argsAll.slice(idx);
const arr = argsAll.splice(0, idx);
var result = (function getFn(sign) {
return new Function(`return [${arr}].reduce((a, b) => a ${sign} b)`)();
})(sign);
return result;
};
return temp;
}
14. 不实用 for 或 while, 仅使用数组内置的方法,创建一个长度为 110 的数组,并且每个元素的值等于数组长度加上下标的值
new Array(110).fill(0).map((item, idx, arr) => arr.length + idx);
15. 判断下列的值
function test(a, b) {
b = a + 10;
console.log(b);
return {
test: function(a, b) {
return test(b, a);
}
};
}
var a = test(100, 200);
a.test(300);
a.test(400);
var b = test(101)
.test(201)
.test(401);
var c = test(102).test(202, 302);
c.test();
耐心做,完全没难度。
16. 二分法
// 普通while循环
function binarySearch(arr, key) {
let low = 0,
high = arr.length - 1;
while (low <= high) {
let mid = parseInt((low + high) / 2);
if (arr[mid] < key) {
low = mid + 1;
} else if (arr[mid] > key) {
high = mid - 1;
} else {
return mid;
}
}
}
// 递归
function binarySearch(arr, key, low = 0, high = arr.length - 1) {
const mid = parseInt((low + high) / 2);
if (arr[mid] < key) {
low = mid + 1;
return binarySearch(arr, key, low, high);
} else if (arr[mid] > key) {
high = mid - 1;
return binarySearch(arr, key, low, high);
} else {
return mid;
}
}
binarySearch([1, 2, 3, 4, 5], 3); // 2
17. 合并两个有效数组
e.g1:
输入: nums1 = [1, 2, 3, 0, 0, 0], m = 3, nums2 = [2, 5, 6], n = 3 输出: [1, 2, 2, 3, 5, 6]
e.g2:
输入: nums1 = [1], m = 1, nums2 = [], n = 0 输出: [1]
/**
* 双指针
* 从两个数组的尾巴开始算起,将大的塞进去,因为是升序数组
*
*/
function merge(nums1, m, nums2, n) {
let p1 = m - 1,
p2 = n - 1,
len = m + n - 1;
while (p2 >= 0) {
nums1[len--] = nums1[p1] > nums2[p2] ? nums1[p1--] : nums2[p2--];
}
return nums1;
}
18. 实现 padEnd
/**
* 如果string字符串长度小于 length 则在右侧填充字符。 如果超出length长度则截断超出的部分。
* @example
padEnd('abc', 6, '_-'); => 'abc_-_'
padEnd('abc', 6, '0'); => 'abc000'
padEnd('abcd', 3); => 'abc'
*/
function padEnd(string, length, chars) {
const sLen = string.length;
if (!chars) {
if (sLen > length) {
return string.substring(0, length);
}
}
const diff = length - sLen;
for (let i = 0; i < diff; i++) {
string += chars;
if (string.length > length) {
return string.substring(0, length);
}
}
return string;
}
19. 实现 isEqual
/**
* 执行深比较来确定两者的值是否相等
* var obj1 = { 'a': 1 };
* var obj2 = { 'a': 1 };
* isEqual(obj1, obj2);
*/
function isEqual(obj1, obj2) {
const obj1Type = toString.call(obj1);
const obj2Type = toString.call(obj2);
if (obj1Type !== obj2Type) return false;
const key1Len = Object.keys(obj1).length;
const key2Len = Object.keys(obj2).length;
if (key1Len !== key2Len) return false;
let flag = false;
Object.keys(obj1).forEach(k => {
flag = obj1[k] === obj2[k];
});
return flag;
}
20. 实现两个大数相加
/**
* JS 在存放整数的时候是有一个安全范围的,一旦数字超过这个范围便会损失精度。
* 实现两个大数相加
* let a = "9007199254740991";
* let b = "1234567899999999999";
*/
let a = '9007199254740991';
let b = '1234567899999999999';
function add(a, b) {
const maxLen = Math.max(a.length, b.length);
// 补0, 方便做相加
if (a.length > b.length) {
b = b.padStart(maxLen, 0);
} else {
a = a.padStart(maxLen, 0);
}
let carry = 0; // 进位
let t = 0;
let sum = '';
for (let i = maxLen - 1; i >= 0; i--) {
t = parseInt(a[i]) + parseInt(b[i]) + carry;
carry = Math.floor(t / 10);
sum = (t % 10) + sum;
}
if (carry === 1) {
sum = `1${sum}`;
}
return sum;
}
21. 请写出快速排序
/**
* 请写出快速排序
* @example
* // test
* var array = [4, 7, 87, 34, 56, 69, 19, 26, 7, 9, 33];
* var result = quicksort(array);
*/
function quicksort(array) {
if (array.length <= 1) return array;
const midIndex = Math.floor(array.length / 2);
const mid = array.splice(midIndex, 1)[0];
let left = [],
right = [];
for (let i = 0; i < array.length; i++) {
if (array[i] < mid) {
left.push(array[i]);
} else {
right.push(array[i]);
}
}
return quicksort(left).concat([mid], quicksort(right));
}
22. 实现 Observer 函数
/**
* 写一个 Observer 函数,实现 如下功能:
* var obj = observe({a:1})
* obj.a = 2 // 打印 a 被修改为 2
*/
function observe(obj) {
return new Proxy(obj, {
get: (target, key) => target[key],
set: (target, key, value) => {
console.log('修改后的值为:' + value);
target[key] = value;
}
});
}