js 常用必备算法_下
setTimeout 实现 setInterval
setTimeout:多久后执行函数
setInterval:多久执行一次函数
function myInterval(fn,interval,...args) {
let context=this
setTimeout(()=>{
fn.apply(context,args)
myInterval(fn,interval,...args)//别忘了为它传入参数
},interval)
}
myInterval((num)=>console.log(num),500,10)
函数柯里化
柯里化又称部分求值,一个柯里化的函数首先会接收一些参数,接收了这些参数后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)©或者 f(a, b)©或者 f(a)(b, c)
function sum(...args1){
return function (...args2) {
return [...args1,...args2].reduce((p,n)=>p+n)
}
}
console.log(sum(1, 2, 2)(7))
防抖节流
防抖
在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新计时,比如在输入框时,我们只是输入了 "测试"两个字,chang 方法会导致事件就执行了很多次。假设我们每一次输入都是和后台进行一次数据交互的话,那执行这么多次事件会很影响性能。那么我们考虑的就是怎样减少与后台数据库请求的次数,那么防抖就应用而生了。也就是说用户触发时间过于频繁,只要最后一次请求的操作就叫做防抖
兼容立即执行和非立即执行
function debounce(func,wait,immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}
//非立即执行版
function debounce(func, wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args)
}, wait);
}
//立即执行版本
function debounce(func,wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
let callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
}}
节流(throttle)
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
对于节流,一般有两种方式可以实现,分别是时间戳版和定时器版。
时间戳版本
function throttle(func, wait) {
let previous = 0;
return function() {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}
}
//定时器版本
function throttle(func, wait) {
let timeout;
return function() {
let context = this;
let args = arguments;
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
堆和栈
Stack 区特点:每个数据顺序存放
Heap 区特点:每个数据随机存放
Stack 和 Heap 的存储规律
数据分两种:非对象 和 对象
非对象都存在 Stack
对象则随机存在 Heap, Stack 里面则存这个对象的地址
Object
定义
无序的数据集合
键值对集合
let obj = new Object({‘name’: ‘frank’})
let obj = {key: value}
key 只能是 字符串, 即使没有引号, 也是字符串
细节
键名是字符串, 不是标识符, 可以包含任意字符
键名引号可以省略, 省略之后只能是标识符
如果你想用 变量 当做 key, 声明如下
let name = 'sun'
let obj = { [a]: 111 }
let obj = {name: 'frank', age: 18}
delete obj.name
obj // {age: 18}
// 这个也是删除, 没有name, 也不报错
delete obj["name"]
// 判断name是不是obj的属性名
"name" in obj // false
let obj = {name: 'frank', age: 18}
Object.keys(obj) // ["name", "age"]
let obj = {name: 'frank', age: 18}
Object.values(obj) // ['frank', 18]
let obj = {name: 'frank', age: 18}
Object.entries(obj) // [["name", "frank"], ['age', 18]]
"toString" in obj // true
obj.hasOwnProperty("toString") // false
in 意思是是否有这个属性, 不管你是不是共有, 只要有就行
hasOwnProperty 意思是拥有自己的属性么?
注意: 共有属性不是自己的属性, 所以他没有 toString
每个对象都有原型
原型里存着对象的共有属性
比如 obj 的原型就是一个对象
obj.proto 存着这个 原型的地址
这个原型对象里有 toString / constructor / valueOf 等属性
对象的原型也是对象
所以对象的原型也有原型
obj 的原型对象 是所有对象的 原型对象
这个原型包含所有对象的共有属性, 是对象的根
这个原型也有原型, 是 null
let obj = {}
obj__proto__ 会找到原型对象Object的共有属性
/*
obj.__proto__ === Object.prototype //true
*/
Object里还有__proto__, 找到是null
/*
obj.__proto__.__proto__ // null
*/
Object.assign() // assign的意思就是赋值
// 小例子
// 意思就是将p1,p2,p3,p4全部赋值给obj
Object.assign(obj,{p1:1, p2:2, p3:3, p4:4})
无法通过自身修改或增加 共有属性
我不服, 我偏要改了他
obj.proto.toString = ‘xxx’ 改了…不建议改
我就想改咋办?? 用 window.Object.prototype 修改
ES6 提供了一个方法, Object.create()