-
实现防抖函数(debounce)
防抖函数原理:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
那么与节流函数的区别直接看这个动画实现即可。
手写简化版:
= null; return (...args) => { clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, args); }, delay); }; };
适用场景:
- 按钮提交场景:防止多次提交按钮,只执行最后提交的一次
- 服务端验证场景:表单验证需要服务端配合,只执行一段连续的输入事件的最后一次,还有搜索联想词功能类似
生存环境请用lodash.debounce
模板引擎实现
data = { name: '姓名', age: 18 } render(template, data); // 我是姓名,年龄18,性别undefined
/\{\{(\w+)\}\}/; // 模板字符串正则 if (reg.test(template)) { // 判断模板里是否有模板字符串 const name = reg.exec(template)[1]; // 查找当前模板里第一个模板字符串的字段 template = template.replace(reg, data[name]); // 将第一个模板字符串渲染 return render(template, data); // 递归的渲染并返回渲染后的结构 } return template; // 如果模板没有模板字符串直接返回 }
实现日期格式化函数
输入:
2020/12/01 dateFormat(new Date('2020-04-01'), 'yyyy/MM/dd') // 2020/04/01 dateFormat(new Date('2020-04-01'), 'yyyy年MM月dd日') // 2020年04月01日
var day = dateInput.getDate() var month = dateInput.getMonth() + 1 var year = dateInput.getFullYear() format = format.replace(/yyyy/, year) format = format.replace(/MM/,month) format = format.replace(/dd/,day) return format }
实现bind方法
bind
的实现对比其他两个函数略微地复杂了一点,涉及到参数合并(类似函数柯里化),因为bind
需要返回一个函数,需要判断一些边界问题,以下是bind
的实现bind
返回了一个函数,对于函数来说有两种方式调用,一种是直接调用,一种是通过new
的方式,我们先来说直接调用的方式- 对于直接调用来说,这里选择了
apply
的方式实现,但是对于参数需要注意以下情况:因为bind
可以实现类似这样的代码f.bind(obj, 1)(2)
,所以我们需要将两边的参数拼接起来 - 最后来说通过
new
的方式,对于new
的情况来说,不会被任何方式改变this
,所以对于这种情况我们需要忽略传入的this
简洁版本
- 对于普通函数,绑定
this
指向 - 对于构造函数,要保证原函数的原型对象上的属性不能丢失
...args) { // this表示调用bind的函数 let self = this; //返回了一个函数,...innerArgs为实际调用时传入的参数 let fBound = function(...innerArgs) { //this instanceof fBound为true表示构造函数的情况。如new func.bind(obj) // 当作为构造函数时,this 指向实例,此时 this instanceof fBound 结果为 true,可以让实例获得来自绑定函数的值 // 当作为普通函数时,this 指向 window,此时结果为 false,将绑定函数的 this 指向 context return self.apply( this instanceof fBound ? this : context, args.concat(innerArgs) ); } // 如果绑定的是构造函数,那么需要继承构造函数原型属性和方法:保证原函数的原型对象上的属性不丢失 // 实现继承的方式: 使用Object.create fBound.prototype = Object.create(this.prototype); return fBound; } ``` ```javascript // 测试用例 function Person(name, age) { console.log('Person name:', name); console.log('Person age:', age); console.log('Person this:', this); // 构造函数this指向实例对象 } // 构造函数原型的方法 Person.prototype.say = function() { console.log('person say'); } // 普通函数 function normalFun(name, age) { console.log('普通函数 name:', name); console.log('普通函数 age:', age); console.log('普通函数 this:', this); // 普通函数this指向绑定bind的第一个参数 也就是例子中的obj } var obj = { name: 'poetries', age: 18 } // 先测试作为构造函数调用 var bindFun = Person.myBind(obj, 'poetry1') // undefined var a = new bindFun(10) // Person name: poetry1、Person age: 10、Person this: fBound { } a.say() // person say // 再测试作为普通函数调用 var bindNormalFun = normalFun.myBind(obj, 'poetry2') // undefined bindNormalFun(12) // 普通函数name: poetry2 普通函数 age: 12 普通函数 this: { name: 'poetries', age: 18} ``` > 注意: `bind`之后不能再次修改`this`的指向,`bind`多次后执行,函数`this`还是指向第一次`bind`的对象 参考:[前端手写面试题详细解答](https://kc7474.com/archives/1333?url=handwritten) ### 模拟Object.create Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 ```javascript // 模拟 Object.create function create(proto) { function F() { } F.prototype = proto