应用型原型方法
防抖
防抖 debounce
function debounce (func, delay) {
let timeout
return function () {
clearnInterval(timeout)
timeout = setInterval(() => {
func.apply(this, arguments)
}, delay)
}
}
节流函数
throttle, 多次调用,只调用一次
function throttle (fuc, delay) {
let isRun = false
return function () {
if (isRun) {
return
}
isRun = true
setTimeout(() => {
func.apply(this, arguments)
isRun = false // 定时器到时间之后,会把开关打开,我们的函数就会被执行
}, delay)
}
}
数组去重
es5实现
function unique () {
const res = arr.filter((item, index, array) => array.indexOf(item) = index
return res
}
es6实现
let unique = arr => [...new Set(arr)]
数组扁平化
es5实现:
1. 递归实现
function flatten (arr) {
let result = [];
arr.forEach(item => {
if (Array.isArray(item)) {
result = result.concat(flatten(item))
} else {
result.push(item)
}
return result
})
}
2. reduce 加递归
function flatten1 (arr) {
return arr.reduce((res, next) => {
return res.concat(Array.isArray(next) ? flatten1(next) : next)
}, [])
}
function faltten2 (arr) {
while(arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr)
}
return arr
}
es6 实现:
1.[1, [2, [3]]].flat(2) // [1, 2, 3]
事件发布订阅
class EventEmitter {
constructor () {
this.cache = {}
}
on (name, fn) {
if (this.cache[name]) {
this.cache[name].push(fn)
} else {
this.cache[name] = [fn]
}
}
off (name, fn) {
let tasks = this.cache[name]
if (tasks) {
const index = tasks.findIndex(f => f === fn || fn.callback === fn)
if (index >= 0) {
tasks.splice(index,1)
}
}
}
emit(name, once = false, ...args) {
if (this.cache[name]) {
let tasks = this.cache[name].slice()
}
for (let fn of tasks) {
fn(...args)
}
if (once) {
delete this.cache[name]
}
}
}
字符串模板
function render(template, data) {
const reg = /{{(\w+)}}/; // 模板字符串正则
if (reg.test(template)) { // 判断模板里是否有模板字符串
const name = reg.exec(template)[1]; // 查找当前模板里第一个模板字符串的字段
template = template.replace(reg, data[name]); // 将第一个模板字符串渲染
return render(template, data); // 递归的渲染并返回渲染后的结构
}
return template; // 如果模板没有模板字符串直接返回
}
let template = '我是{{name}},年龄{{age}},性别{{sex}}';
let person = {
name: '布兰',
age: 12
}
render(template, person); // 我是布兰,年龄12,性别undefined
对象深拷贝和浅拷贝
浅拷贝
浅拷贝时创建一个对象, 这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是 基本类型的值。如果属性是引用类型,拷贝的就是内存地址,如果其中一个对象改变了这个地址,就会影响到另一个对象。
常见的浅拷贝方式
- Object.assign
- es6 展开符
- contact 数组的一个克隆方式
- slice 数组克隆
常见的深拷贝方式
-
JSON.parse(JSON.stringfy()) 局限性(处理后正则变成了空对象, 函数变成了null)
1.如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式,而不是对象的形式
2.如果obj里有RegExp(正则表达式的缩写)、Error对象,则序列化的结果将只得到空对象;
3、如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
4、如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
5、JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;
6、如果对象中存在循环引用的情况也无法正确实现深拷贝;
-
函数库 loash的_.cloneDeep
-
Jquery.extend
-
手写递归函数
// 手写深拷贝函数 function deepClone(obj) { if (obj === null) return obj if (obj instanceof Date) return new Date(obj) // 重新拷贝 if (obj instanceof RegExp) return new RegExp() if (typeof obj !== "object") return obj const targetclone = Array.isArray(obj)? []:{} for(let prop in target) { if(target.hasOwnProperty(prop)) { targetclone[prop] = (typeof target[prop] === 'object')? deepClone(target[prop]):target[prop] } } return targetclone }
深拷贝
深拷贝是将一个对象从内存中完整的拷贝一份出来。 从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。浅拷贝共享一块内存, 深拷贝与原对象共享一块内存空间
// 手写深拷贝函数
function deepClone(obj) {
if (obj === null) return obj
if (obj instanceof Date) return new Date(obj) // 重新拷贝
if (obj instanceof RegExp) return new RegExp()
if (typeof obj !== "object") return obj
const targetclone = Array.isArray(obj)? []:{}
for(let prop in target) {
if(target.hasOwnProperty(prop)) {
targetclone[prop] = (typeof target[prop] === 'object')?
deepClone(target[prop]):target[prop]
}
}
return targetclone
}
手写ajax
function ajax (method, url) {
let xmlhttp
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest()
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
}
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200 ) {
console.log(xml.responseText)
}
}
xmlhttp.open(method, url, true)
xmlhttp.send()
}
函数柯里化
函数柯里化概念: 柯里化(Currying)是把接受多个参数的函数转变为接受一个单一参数的函数,并且返回接受余下的参数且返回结果的新函数的技术。
function add () {
console.log(arguments)
let args = Array.prototype.slice.call(arguments)
}
// add(1,2)(12,23)(12)
数组原型方法
原型链方法
call
Function.prototype._call = function (context, ...args) {
let context = context || window; // 不传this则指向window
const key = Symbol()
context[key] = this
const result = context[key](...args)
//删除添加的属性
delete context[key]
//返回函数调用的返回值
return result
}
Funtion.rptotype._myCall = function (context){
if (typeof this !== "function") {
console.error("type error")
}
let args = [...arguments].slice(1)
let result = null
context = context || window
const key = symbol()
context[key] = this
result = context[key](...args)
delete context[key]
return result
}
apply
Function.prototype._apply = function (context, args) {
let context = context || window; // 不传this则指向window
const key = Symbol()
context[key] = this
const result = context[key](...args)
//删除添加的属性
delete context[key]
//返回函数调用的返回值
return result
}
Function.prototype.MyApplay = function (context) {
if (typeof this !== "function") {
console.error("type error")
}
let result = null
context = context || windows
const key = symbol()
context[key] = this
if (arguments[1]) {
result = context[key](...argments[1])
} else {
result = context[key]()
}
delete context[key]
return result
}
bind
Function.prototype._bind = function (context, ...args) {
let fn = this
let args = args ? args : []
return function NewFn (...newFnArgs) {
if (this instanceof newFn) {
return new fn(...args, ...newFnArgs)
}
return fn.apply(context, [...args,...newFnArgs])
}
}