# 模拟实现
# call模拟实现
思路
自定义该对象一个属性,值为该执行的函数, this可以获取到需要调用到函数
执行函数, 传入参数(...args), 获取返回值
删除函数
返回值
Function.prototype.call2 = function (context, ...args) {
var context = context || window
// this 指的是调用它函数
context.fn = this
var result = context.fn(...args)
delete context.fn
return result
}
# apply 模拟实现
实现和call一样。只是传入参数传入是数组的形式
Function.prototype.apply2 = function (context, arr) {
var context = context || window
// this 指的是调用它函数
context.fn = this
var result = context.fn(...arr)
delete context.fn
return result
}
# bind 模拟实现
返回一个函数
可以传入参数, 可以在bind时候传入,也可以在返回函数的时候传入,两个参数拼接起来
可以返回函数,用构造函数创建,this指向实例
JavaScript深入之bind的模拟实现 (opens new window)
Function.prototype.bind = function (context, ...arr) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
const _self = this // bar
const fBound = function (...bindArr) {
// 如果是构造函数,那么this就是实例,那么通过instanceof 判断是true,是构造函数,否则就函数调用
// 处理返回值
return _self.apply(this instanceof fBound ? this : context, [...arr, ...bindArr])
}
// 返回的函数fBound继承一下当前调用函数的bar的原型
fBound.prototype = Object.create(_self.prototype)
// 等价于
// function f () {}
// f.prototype = _self.prototype
// fBound.prototype = new f()
return fBound
}
# new 实现
function objectFactory (constructor, ...args) {
const obj = Object.create(null)
obj._proto = constructor.prototype // 创建对象原型指向构造函数的原型上
const result = constructor.apply(obj, [...args]) // 执行构造函数, 改变this
return typeof result === 'object' ? result : obj // 如果构造函数返回对象,才返回,如果是基本类型则还是返回创建对象
}
# 防抖
function debounce (fn, wait) {
let timeout result
return function (...args) {
if (timeout) clearTimeOut(timeout)
timeout = setTimeOut(() => {
fn.apply(this, args)
}, wait)
}
}
function debounce (fn, wait, immediate = false) {
let timeout, result
const debounced = function (...args) {
if (timeout) clearTimeout(timeout)
if (immediate) {
// 立即执行函数,停止n秒后才能再次触发
// 如果已经执行过,就不会再执行
const callNow = !timeout
timeout = setTimeout(() => {
timeout = null
}, wait)
if (callNow) result = fn.apply(this, args)
} else {
timeout = setTimeout (() => {
fn.apply(this, args)
}, wait)
}
// 由于setTimeOut是延时执行,所以拿不到返回值
// 当immediate为true 有返回值,false则为undefined
return result
}
// 取消事件
debounced.cancel = function() {
clearTimeout(timeout)
timeout = null
}
return debounced
}
# 节流
function throttle(fn, wait) {
let timeout
return function (...args) {
if (!timeout) {
timeout = setTimeOut(() => {
timeout = null
fn.apply(this, args)
}, wait)
}
}
}
function throttle(func, wait, options) {
var timeout, context, args, result;
var previous = 0;
if (!options) options = {};
var later = function() {
previous = options.leading === false ? 0 : new Date().getTime();
timeout = null;
func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function() {
var now = new Date().getTime();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
};
throttled.cancel = function() {
clearTimeout(timeout);
previous = 0;
timeout = null;
}
return throttled;
}
# 深/浅拷贝
slice、concat, JSON.stringify
function shallowCopy (obj) {
if (typeof obj !== 'object') return
var newObj = obj instanceOf Array ? [] : {}
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key]
}
}
}
function deepCopy (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]
}
}
}
# 柯里化
元是指函数传入的参数,一个参数叫做一元
柯里化就是一个n元函数转化成n个一元函数
一个函数转多多个
# 偏函数
局部应用
一个转一个
固定一个函数的一个或者多个参数
一个n 元函数转化成 一个 n - x 元 函数
两者的关系
柯里化 应用在偏函数中
# 惰性函数
原理是重写函数名字
var foo = function() {
var t = new Date();
foo = function() {
return t;
};
return foo();
};