1,节流防抖
代码实现:
function throttle(func,wait){
var previous = 0
return function(){
var now = +new Date()
if(now - previous > wait){
func.apply(this,arguments)
previous = now;
}
}
}
// 节流函数常用在高频点击提交,表单重复提交
function debounce(func,wait){
var timer
return function(){
if(timer) clearTimeout(timer)
timer = setTimeout(function(){
func.apply(this,arguments)
},wait)
}
}
// 防抖函数常用在:1,input框search减少资源请求次数(输入后200秒内没有操作才会触发请求接口)2,window的resize事件,防止重复渲染。
// 区别
// 防抖是将多次执行变为只执行一次,类似于王者荣耀的回城特效,只认最后一次。动作发生后,在规定时间内重新触发,则重新计算时间。节流是将多次执行变为每隔一段时间执行,动作发生后,在规定时间重新触发会被无视。
2,Set, Map、weakset、weakMap
使用场景:
3,数组扁平化
方法一:
arr.join(',').split(',').sort((a,b) => a - b).map(Number)</pre>
方法二:
a = arr.flat(4)
b = Array.from(new Set(a))
c = b.sort((a, b)=>a-b)</pre>
方法三:
const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));
deepFlatten(arr).sort((a, b)=>a-b)</pre>
方法四:
[...new Set(arr.toString().split(','))].sort((a,b)=>a-b)
4,实现一个new
先理清楚 new 关键字调用函数的具体过程,那么写出来就很清楚了
首先创建一个空的对象,空对象的proto属性指向构造函数的原型对象
把上面创建的空对象赋值构造函数内部的this,用构造函数内部的方法修改空对象
如果构造函数返回一个非基本类型的值,则返回这个值,否则返回上面创建的对象
function _new(fn, ...arg) {
var obj = Object.create(fn.prototype);
const result = fn.apply(obj, ...arg);
return Object.prototype.toString.call(result) == '[object Object]' ? result : obj;
}
apply的含义:
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
5,单个或者多个数组合并去重
function combine(){
let arr = [].concat.apply([],arguments);
return Array.from(new Set(arr))
}
//合并两个数组
var a = [1,2,3];
var b = [4,5,6];
var newA = [...a,...b]
6,ES5组合继承
function SuperType(name){
this.name = name
this.gender = 'male'
}
SuperType.prototype.getName = function(){
console.log(this.name)
}
function SubType(name,age){
SuperType.call(this,name)
this.age = age
}
SubType.prototype = new SuperType()
SubType.constructor = SubType
SubType.prototype.getAge = function(){
console.log(this.age)
}
subtype = new SubType('小明', 21)
原理:
1,SuperType.call(this)使得子类继承父类属性,SuperType.call(this,name)传name参数使得子类以传值的继承并改变父类属性值
2,SubType.prototype = new SuperType()使得子类继承父类方法
缺点:
1,调用了两次父类构造函数
2,子类的原型上多了不需要的属性,造成内存资源的浪费
7,寄生组合继承
function inheritPrototype(subType,superType){
let prototype = Object.create(superType.prototype);//创建父类的副本
prototype.constructor = subType;//为创建的副本定义constructor
subType.prototype = prototype;//将父类的副本赋值给子类
}
function SuperType(name){
this.name = name
}
SuperType.prototype.getName = function(){
console.log(this.name)
}
function SubType(name,age){
SuperType.call(this,name);
this.age = age
}
inheritPrototype(SubType, SuperType)
SubType.prototype.getAge = function(){
console.log(this.age)
}
上面的代码等同于下面:
function SuperType(name){
this.name = name
}
SuperType.prototype.getName = function(){
console.log(this.name)
}
function SubType(name,age){
SuperType.call(this,name);
this.age = age
}
SubType.prototype = Object.create(SuperType.prototype);
SubType.constructor = SubType
SubType.prototype.getAge = function(){
console.log(this.age)
}
优缺点:
1,避免了两次调用父类构造函数
2,解决了组合继承造成的子类的原型上多了不需要的属性的问题,节省内存资源
8,浅拷贝和深拷贝
-
浅拷贝
方法一:
// ES6展开运算符
// 浅拷贝数组
let a = [1,2,3]
let b = [...a]
b.push(4)
a // [1,2,3]
b // [1,2,3,4]
// b与a互相不影响
// 浅拷贝对象
let aaa = {a:1,b:2}
let bbb = {...aaa}
bbb.a = 3
bbb // {a: 3, b: 2}
aaa // {a: 1, b: 2}
// aaa与bbb互不影响
方法二:
// Object.assign
// 浅拷贝数组
let a = [1,2,3]
let b = Object.assign([],a)
b.push(4)
a // [1,2,3]
b // [1,2,3,4]
// b与a互相不影响
// 浅拷贝对象
let aaa = {a:1,b:2}
let bbb = Object.assign({},aaa)
bbb.a = 3
bbb // {a: 3, b: 2}
aaa // {a: 1, b: 2}
// aaa与bbb互不影响
* **深拷贝**
方法一:
// JSON.stringfy
let obj1 = {
a:1,
b:{
b1:1
}
}
let obj2 = JSON.parse(JSON.stringfy(obj1))
obj2.b.b1 = 2;
obj2 // {a:1,b:{b1:2}}
obj1 // {a:1,b:{b1:1}}
// obj2改变不会影响obj1
方法二:
var deepCopy = function(obj) {
if (typeof obj !== 'object') return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
9,Async/Await 如何通过同步的方式实现异步
基本概念:async/await是使用generator+run函数(自动执行generator)
1,Async/Await是参照Generator封装的一套异步处理方案,本质是generator的语法糖
2,generator依赖于迭代器Iterator
3,Iterator思想来源于单向链表
**所以源头来源于单向链表**
* 单向链表实现
* Iterator迭代器简单实现
const makeIterator = arr =>{
let nextIndex = 0
return {
next: ()=>{
nextIndex<arr.length? {value:arr[nextIndex++],done:false}:{value:'undefined',done:true}
}
}
}
const it = makeIterator(['神话','金喜善'])
it.next() // {value:'神话',done:false}
it.next() // {value:'金喜善',done:false}
it.next() // {value:undefined,done:true}
10,ES6继承
class SuperType {
constructor(name,gender){
this.name = name
this.gender = gender
}
getName(){
console.log(this.name)
}
}
class SubType extend SuperType {
constructor(name,age){
super(this);
this.age = age
}
getAge(){
console.log(this.age)
}
}
10,Call,Apply,Bind实现
// call
Function.prototype.myCall = function (context) {
context = context ? Object(context) : window
context.fn = this;
let args = [...arguments].slice(1);
const result = context.fn(...args);
delete context.fn;
return result;
}
// apply
Function.prototype.myApply = function (context) {
context = context ? Object(context) : window;
context.fn = this;
let args = [...arguments][1];
let result;
if (args.length === 0) {
result = context.fn();
} else {
result = context.fn(args);
}
delete context.fn;
return result;
}
// bind
Function.prototype.myBind = function (context) {
let self = this;
let args = [...arguments].slice(1);
return function() {
let newArgs = [...arguments];
return self.apply(context, args.concat(newArgs));
}
}
11,基本排序
- 使用原生sort函数
function originSort(arr){
return arr.sort((a,b)=>a-b)
}
- 冒泡排序
function bubbleSort(arr){
if (arr.length<=1) return arr
for(let i = 0;i<arr.length-1;i++){
for(let j=i+1;j<arr.length;j++){
if(arr[j]<arr[i]){
[arr[j],arr[i]]=[arr[i],arr[j]]
}
}
}
return arr
}
- 选择排序
function chooseSort(arr){
let oldArr = arr
let newArr = []
function findMinNumber(param){
return Math.min.apply(null,...arguments)
}
while(oldArr.length){
let minValue = findMinNumber(oldArr)
let minValueIndex = arr.indexOf(minValue)
oldArr.splice(minValueIndex,1)
newArr.push(minValue)
}
return newArr
}
9,深拷贝
function deepClone(obj){
var newObj= obj instanceof Array ? []:{};
for(var item in obj){
var temple= typeof obj[item] == 'object' ? deepClone(obj[item]):obj[item];
newObj[item] = temple;
}
return newObj;
}
10,阶乘
n! = n*(n-1)!;
function mul (n){
if(n == 1){
return 1;
}
return n*mul(n-1);
}
11,斐波那契数列
function fb(n){
if( n == 1 ||n ==2 ){
return 1;
}
return fb(n-1) + fb(n-2);
}</pre>
### 12,函数柯里化
var add = (a, b, c) => a + b + c
function curry(fn, ...args) {
const length = fn.length
let lists = args || []
let listLen
return function (..._args) {
lists = [...lists, ..._args]
listLen = lists.length
if (listLen < length) {
const that = lists
lists = []
return curry(fn, ...that)
} else if (listLen === length) {
const that = lists
lists = []
return fn.apply(this, that)
}
}
}
### 13,代码组合
var toUpperCase = (str) => str.toUpperCase()
var reverse = (arr) => arr.reverse()
var head = (arr) => arr[0]
var reverseHeadUpperCase = (arr) => toUpperCase(head(reverse(arr)))
var compose = (...args) => (initValue) => args.reduceRight((a, c) => c(a), initValue)
### 14,发布订阅
class EventEmiter {
constructor() {
this.events = {}
}
emit(event, ...args) {
this.events[event].forEach(fn => {
fn.apply(this, args)
})
}
on(event, fn) {
if (this.events[event]) {
this.events[event].push(fn)
} else {
this.events[event] = [fn]
}
}
remove(event) {
delete this.events[event]
}
}
const eventHub = new EventEmiter()
eventHub.on('test', data => {
console.log(data)
})
eventHub.emit('test', 1)
console.log(2)
### 15,手写promise
//初始版本的promise
function myPromise(constructor){
let self=this;
self.status="pending" //定义状态改变前的初始状态
self.value=undefined;//定义状态为resolved的时候的状态
self.reason=undefined;//定义状态为rejected的时候的状态
function resolve(value){
//两个==="pending",保证了状态的改变是不可逆的
if(self.status==="pending"){
self.value=value;
self.status="resolved";
}
}
function reject(reason){
//两个==="pending",保证了状态的改变是不可逆的
if(self.status==="pending"){
self.reason=reason;
self.status="rejected";
}
}
//捕获构造异常
try{
constructor(resolve,reject);
}catch(e){
reject(e);
}
}
myPromise.prototype.then=function(onFullfilled,onRejected){
let self=this;
switch(self.status){
case "resolved":
onFullfilled(self.value);
break;
case "rejected":
onRejected(self.reason);
break;
default:
}
}
// 异步调用的promise
function myPromise(constructor){
let self=this;
self.status="pending" //定义状态改变前的初始状态
self.value=undefined;//定义状态为resolved的时候的状态
self.reason=undefined;//定义状态为rejected的时候的状态
self.onFullfilledArray=[];
self.onRejectedArray=[];
function resolve(value){
if(self.status==="pending"){
self.value=value;
self.status="resolved";
self.onFullfilledArray.forEach(function(f){
f(self.value);
//如果状态从pending变为resolved,
//那么就遍历执行里面的异步方法
});
}
}
function reject(reason){
if(self.status==="pending"){
self.reason=reason;
self.status="rejected";
self.onRejectedArray.forEach(function(f){
f(self.reason);
//如果状态从pending变为rejected,
//那么就遍历执行里面的异步方法
})
}
}
//捕获构造异常
try{
constructor(resolve,reject);
}catch(e){
reject(e);
}
}
// then 方法
myPromise.prototype.then=function(onFullfilled,onRejected){
let self=this;
switch(self.status){
case "pending":
self.onFullfilledArray.push(function(){
onFullfilled(self.value)
});
self.onRejectedArray.push(function(){
onRejected(self.reason)
});
case "resolved":
onFullfilled(self.value);
break;
case "rejected":
onRejected(self.reason);
break;
default:
}
}
// 链式调用
myPromise.prototype.then=function(onFullfilled,onRejected){
let self=this;
let promise2;
switch(self.status){
case "pending":
promise2=new myPromise(function(resolve,reject){
self.onFullfilledArray.push(function(){
try{
let temple=onFullfilled(self.value);
resolve(temple)
}catch(e){
reject(e) //error catch
}
});
self.onRejectedArray.push(function(){
try{
let temple=onRejected(self.reason);
reject(temple)
}catch(e){
reject(e)// error catch
}
});
})
case "resolved":
promise2=new myPromise(function(resolve,reject){
try{
let temple=onFullfilled(self.value);
//将上次一then里面的方法传递进下一个Promise的状态
resolve(temple);
}catch(e){
reject(e);//error catch
}
})
break;
case "rejected":
promise2=new myPromise(function(resolve,reject){
try{
let temple=onRejected(self.reason);
//将then里面的方法传递到下一个Promise的状态里
resolve(temple);
}catch(e){
reject(e);
}
})
break;
default:
}
return promise2;
}
### 16,回文字符串
function countSubstrings(s) {
const n = s.length;
let ans = 0;
for (let i = 0; i < 2 * n - 1; ++i) {
let l = i / 2, r = i / 2 + i % 2;
while (l >= 0 && r < n && s.charAt(l) == s.charAt(r)) {
--l;
++r;
++ans;
}
}
return ans;
};
### 17,给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。
nums = [2,7,11,15];
var result = {};
for (var i = 0; i < nums.length; i++) {
result[nums[i]] = i;
}
console.log(result)
var twoSum = function(nums, target) {
let result = {};
let length = nums.length;
for (var i = 0; i < length; i++) {
let difference = target - nums[i];
if (difference in result) {
return [result[difference], i]
}
result[nums[i]] = i;
}
};