[toc]
手写代码
数组扁平化
//demo1
function flatten(arr) {
let result = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]));
} else {
result = result.concat(arr[i]);
}
}
return result;
}
//demo2
const flattenArray = (arr) => Array.isArray(arr) ? arr.reduce((a, b) => [...a, ...flattenArray(b)], []) : [arr]
//demo3
function flatten(arr) {
if(Array.isArray(arr)){
arr.toString().split(",").map(function(item){
return Number(item)
})
}
}
防抖和节流
防抖(debounce)
所谓防抖,就是指触发事件后 n 秒后才执行函数, 如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
举个例子:我连续输入100个字母,在输入最后一个字母后,再等200毫秒,执行请求接口。
- 防抖的含义就是让某个时间期限内(约定200毫秒),事情处理函数只执行一次。
// 防抖
function debounce(func,wait){
let timeout = null //借助闭包
return function() {
if(timeout) clearTimeout(timeout)
timeout = setTimeout(() => {
func();
}, wait); // 简化写法
}
}
节流(throttle)
所谓节流,就是指连续触发事件但是在 n秒中只执行一次函数。
举个例子:我连续输入100个字母,在输入过程中,每隔300毫秒就请求一次接口。也就是说等输入完100个字母,会请求很多次接口。
- 节流的含义就是在某个时间期限,每隔(预定300毫秒)执行一次。
//节流
function throttle(func,wait){
let canRun = true;
return function(){
if(!canRun) return false;
canRun = false;
setTimeout(() => {
func();
canRun = true;
}, wait);
}
}
总结
如果事件触发是高频但是有停顿时,可以选择debounce; 在事件连续不断高频触发时,只能选择throttle,因为debounce可能会导致动作只被执行一次,界面出现跳跃。
深拷贝和浅拷贝
前提
- 防止赋值之后互相影响
- 引用值存储在堆里,且存储的是一个指针
- 该指针指向内存中的某个位置,该位置存储变量的实际值
var a = 2;
var a_copy = a;
a_copy = 3;
console.log("a="+a);//2
console.log("a_copy="+a_copy);//3
var b = [1,2,3];
var b_copy = b;
b_copy.push(5);
console.log("b="+b);//1,2,3,5
console.log("b_copy="+b_copy);//1,2,3,5
浅拷贝
就是只复制对象的第一层,如果对象有嵌套,内部不会复制。
第一层不相等,第二层都相等
var obj = {
a: 1,
b: 2,
c: 3
}
//浅拷贝
function shallowClone(obj){
let cloneObj = {};
for(let i in obj){
cloneObj[i] = obj[i];
}
return cloneObj;
}
var obj2 = shallowClone(obj);
console.log(obj)//
console.log(obj2)//
console.log(obj === obj2)//false
console.log(obj.c === obj2.c);//true
深拷贝
拷贝的时候会生成一份新的数据,修改拷贝以后的数据不会改变原数据。
function deepCopy(obj, cache = new WeakMap()) {
if (!obj instanceof Object) return obj
if (cache.get(obj)) return cache.get(obj) // 防止循环引用
if (obj instanceof Function) { // 支持函数
return function () {
obj.apply(this, arguments)
}
}
if (obj instanceof Date) return new Date(obj) // 支持日期
if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags)
// 支持正则对象
// 还可以增加其他对象,比如:Map, Set等,根据情况判断增加即可,面试点到为止就可以了
const res = Array.isArray(obj) ? [] : {} // 数组是 key 为数字索引的特殊对象
cache.set(obj, res) // 缓存 copy 的对象,用于处理循环引用的情况
Object.keys(obj).forEach((key) => {
if (obj[key] instanceof Object) {
res[key] = deepCopy(obj[key], cache)
} else {
res[key] = obj[key]
}
});
return res
}
柯里化
所谓"柯里化",就是把一个多参数的函数,转化为单参数函数。
// 柯里化之前
function add(x, y) {
return x + y;
}
add(1, 2) // 3
// 柯里化之后
function addX(y) {
return function (x) {
return x + y;
};
}
addX(2)(1) // 3
进一步抽象
function currying (fn, ...args1) {
return function (...args2) {
return fn(...args1, ...args2)
}
}
var increment = currying(add, 1)
increment(2) === 3
// true
var addTen = currying(add, 10)
addTen(2) === 12
手写柯里化:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数
function add(){
var args = Array.prototype.slice.call(arguments);
let inner = function(){
args.push(...arguments);
return inner;
}
inner.toString = function(){
return args.reduce((p,n)=>p+n)
}
return inner;
}
//测试求和
add(1,2,3,4)(5,6)(7) || add(1)(2)(3)(4)
有效大括号(leetcode 20)
var isValid = function(str){
var map = {
"{":"}",
"[":"]",
"(":")"
}
if(str.length % 2 === 1) return false;
var res = [];
for(var i = 0;i < str.length;i++){
if(map[str[i]]){
res.push(str[i]);
} else {
var a = res[res.length-1];
if(map[a] == str[i]) {
res.pop()
} else {
return false;
}
}
}
return res.length===0;
}
检索url参数
function query(){
let url = window.location.search.split("?")[1];
let params = url.split("&");
const param = {};
params.forEach(
(i) => {
let item = i.split("=");
param[item[0]] = item[1];
}
);
console.log(param);
return param;
}