Function.prototype.myBind = function(context) {
//返回一个绑定this的函数,我们需要在此保存this
let self = this
// 可以支持柯里化传参,保存参数
let arg = [...arguments].slice(1)
// 返回一个函数
return function() {
//同样因为支持柯里化形式传参我们需要再次获取存储参数
let newArg = [...arguments]
console.log(newArg)
// 返回函数绑定this,传入两次保存的参数
//考虑返回函数有返回值做了return
return self.apply(context, arg.concat(newArg))
}
}
function createCache(){
const data={}//需要缓存的数据
return {
set:(key,val)=>{
data[key]=val
},
get:key=>data[key]
}
}
const c=createCache()
c.set('name','张三')//设置缓存的数据
const name=c.get('name')//获取缓存中的数据
console.log(name)
property
:修改对象属性, 不会体现html结构中attribute
:修改html属性,会改变html结构树(DOM结构)
DOM查询做缓存
//不缓存DOM查询结果
for(let i=0;i<document.getElementByTagName('p').length;i++){
//每次循环,都会计算length,频繁进行DOM查询
}
//缓存DOM查询结果
const pList=document.getElementByTagName('p')
const pLength=pList.length
for(let i=0;i<length;i++){
//缓存length,只进行一次DOM查询
}
将频繁操作改为一次性操作
const listNode =document.getElementById('list')
//创建一个文档片段,此时还没有插入到DOM树中
const frag=document.createDocumentFragment()
//执行插入
for(let i=0;i<10;i++){
const li=document.createElement('li')
li.innerHTML=`第${i}个li`
frag.appendChild(li)
}
//循环结束后再插入到dom树中
listNode.appendChild(flag)
function bindEvent(elem,type,selector,fn){
if(fn==null){//说明不需要代理
fn=selector
selector=null
}
elem.addEventListener(type,e=>{
let target
if(selector){
//需要代理
target=e.target
//元素被指定的选择器字符串选择,Element.matches() 方法返回true; 否则返回false
if(target.mathes(selector)){
fn.call(target,e)
}else{
//不需要代理
fn(e)
}
}
})
}
防止频繁向服务器发送请求
// 防抖
debounce(fn, delay = 500) {
// timer是闭包中的
let timer = null
return function () {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, delay)
}
}
每隔一段时间触发一次
// 节流
throttle(fn, delay = 100) {
// timer是闭包中的
let timer = null
return function () {
if (timer) {
return
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, delay)
}
}
var
声明的变量,其作用域为该语句所在的函数内
,并且存在变量提升let
声明的变量,其作用域为该语句所在的代码块内,不存在变量提升const
声明的是常量,不能修改这个常量,且需要赋初始值//判断是否为对象类型
function isObject(obj){
return typeof obj==='object'&&obj!==null
}
//深度比较两个值
function isEqual(obj1,obj2){
//判断是否为对象
if(!isObject(obj1)||!isObject(obj2)){
//说明是值类型
return obj1===obj2 //直接比较
}
//说明传入的两个元素为同一个元素直接返回true
if(obj1===obj2){
return true
}
//判断两个对象属性个数是否相等
//如果不相等则返回false
const obj1Keys=Object.keys(obj1)
const obj2Keys=Object.keys(obj2)
if(obj1Keys.length!==obj2Keys.length){
return false
}
//使用递归进行深度比较,以obj1为基准作比较
for(let key in obj1){
const res=isEqual(obj1[key],obj2[key])
//判断res结果,如果为false说明不相等,直接返回false
if(!res){
return false
}
}
return true
}
例如:
'1-2-3'.split('-')//[1,2,3]
[1,2,3].join('-')//'1-2-3'
pop
弹出数组最后一个元素,返回结果为弹出的元素
const arr=[10,20,30,40]
const arrRes=arr.pop()
console.log(arrRes)//40
push
添加元素到数组最后一个,返回结果为数组长度
const arr=[10,20,30,40]
const arrRes=arr.push(50)
console.log(arrRes)//返回为数组长度
unshift
添加元素到数组第一个,返回结果为数组长度
const arr=[10,20,30,40]
const arrRes=arr.unshift(50)
console.log(arrRes)//返回为数组长度
shift
移除数组第一个元素,返回结果为数组长度
const arr=[10,20,30,40]
const arrRes=arr.unshift(50)
console.log(arrRes)//返回为数组长度
这些函数都会改变原数组
补充:
纯函数
常见纯函数有
非纯函数有
slice()
- 截取数组元素
参数1
:开始截取的索引位置参数2(可选)
:结束截取的索引位置- 不写参数2将截取参数1后所有元素
- 返回一个新的数组
const arr=[10,20,30,40]
const arrRes=arr.slice(1,3)
console.log(arrRes)//[20,30,40]
splice()
- 截取数组元素
参数1
:开始剪贴的索引位置参数2
:剪贴的个数- 参数n(可选):在剪贴的位置插入的元素
- 会改变原数组
const arr=[10,20,30,40]
const arrRes=arr.splice(1,2,'a','b')
console.log(arrRes)//[10,'a','b',40]
fn.call(this,p1,p2,p3)
fn.apply(this,arguments)
传参形式不同,call以依次传入方式传参,而apply以数组形式传参
闭包
特性
影响
String.prototype.trim=function(){
return this.replace(/^\s+/,'').replace(/\s+$/,'')
}
function getUrl(url) {
var urlObj={}
var arr=url.split("?")[1].split('&')
for(var i=0;i<arr.length;i++){
var newArr=arr[i].split('=')
urlObj[newArr[0]]=newArr[1]
}
return urlObj
}
let arr=[1,2,3,[4,5,[6,7]]]
//方式一:递归
function flat(arr){
//验证arr是否存在深层嵌套
const isDeep=arr.some(item=>item instanceof Array)
if(!isDeep){//说明不存在深层嵌套
return arr
}
const res=[].concat(...arr)
return flat(res)//使用递归
}
//方式二:字符串tostring
function flat(arr){
return arr.toString().split(',').map(item=>{
return Number(item)
})
}
//方式三:json.stringify(更麻烦)
//JSON.stringify(arr):"[1,2,3,[4,5,[6,7]]]"
//replace(/\[|\]/ig,"") '"1","2","3","4","5","6""7"'
//最后使用map将字符串类型转换成数字类型
function flat(arr){
return JSON.stringify(arr).replace(/\[|\]/g,"").split(',').map(item=>{
return Number(item)
})
}
方式一 (传统方式)
function unique(arr){
const res=[]
arr.foreach(item=>{
if(res.indexOf(item)<0){//说明不存在
res.push(item)
}
})
return res
}
方式二 (set)
function unique(arr){
const set=new Set(arr)
return [...set]
}