1.JS柯里化
概念
百度百科:在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。通俗点说就是将一个函数拆分成多个函数,是固定部分参数,返回一个接受剩余参数的函数,也称为部分计算函数,目的是为了缩小适用范围,创建一个针对性更强的函数;
- 问题
如何实现一个函数满足sum(1,2,3,4,5,6)或sum(1)(2)(3)(4)(5)(6)输出结果都为21?
function sum() {
var args = [...arguments];
//针对()()()这类调用方式,利用必包特性将参数存储
var _sum = function() {
args = [...args, ...arguments];
return _sum;
}
//自执行函数,计算参数之和
_sum.toString = function() {
const v = args && args.length && args.reduce((a, b) => a + b)
return v;
}
return _sum;
}
var v = sum(1,2,3,4,5,6);
var b = sum(1)(2)(3)(4)(5)(6);
console.log(v, 'sum',b) //21 sum 21
2.防抖
当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
3.节流
当持续触发事件时,保证在一定时间内只调用一次事件处理函数。
问题
如何实现一个防抖函数?
如何实现一个节流函数?
- 防抖
var timer1 = null;
function clickFn(time) {
if (timer1 != null) clearTimeout(timer1);
timer1 = setTimeout(function() {
console.log('防抖')
},time)
}
- 节流
var timer = null;
function clickFn2(time) {
if (!timer) {
timer = setTimeout(function() {
console.log('节流');
timer = null;
}, time)
}
}
4.如何实现一个变量a,满足 a == 1 && a == 2 && a == 3或者a=1 && a=2&&a===3返回true?
//此种可以满足严格和宽松两种等模式
var i = 1;
Object.defineProperty(window, 'a', {
get() {return i++}
})
//此种模式或toString方式只能满足宽松模式==,严格模式下不会进行数据转换,直接对值进行比较
var a = {
i: 1,
valueOf() {
return this.i++
}
}
5.void 0 与undefined区别?
- void 0 替换undefined后能节省不少字节的大小;
- undefined在低版本 IE 中可以重写如: var undefined = 10; 这样会影响代码中undefined的判断;
- undefined 在 ES5 中已经是全局对象的一个只读(read-only)属性了,它不能被重写。但是在局部作用域中,还是可以被重写的。
(function() { var undefined = 10; // 10 -- chrome alert(undefined); })();
- void 运算符能对给定的表达式进行求值,然后返回 undefined,也就是说,void 后面你随便跟上一个表达式,返回的都是
undefined,都能完美代替 undefined!那么,这其中最短的是什么呢?毫无疑问就是 void 0 了;void是不能被重写的;
6.call、apply、bind共同点及区别?如何手动实现以上三个函数?
共同点: 三者都是改变函数体内this的指向;
不同点:
call、apply的区别:接受参数的方式不一样,call(fn, p1,p2,p3…),apply(fn,[p1,p2,p3…])为数组, 返回函数执行结果;
bind:不立即执行。而apply、call 立即执行。返回函数的拷贝,并拥有指定的this和初始参数;
- apply实现
Function.prototype.MyApply = function(context) {
if (typeof this !== 'function') {
throw new TypeError('not function!');
}
context = context || window;
context.fn = this;
let result;
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
delete context.fn;
return result;
}
- call实现
Function.prototype.MyCall = function(context) {
//判断当前是否函数调用
if (typeof this !== 'function') {
throw new TypeError('not funciton');
}
context = context || window;
context.fn = this;
let args = [...arguments].slice(1);
let result = context.fn(...args);
delete context.fn;
return result;
}
- bind实现
Function.prototype.MyBind = function(context) {
if (typeof this !== 'function') {
throw new TypeError('not function!');
}
let _this = this
let arg = [...arguments].slice(1);
return function F() {
// 处理函数使用new的情况
if (this instanceof F) {
return new _this(...arg, ...arguments)
} else {
return _this.apply(context, arg.concat(...arguments))
}
}
}
- 拓展bind使用场景
想让下面代码输出1,2,3,4,5?
for (var i = 1; i <= 5; i++) {
setTimeout(function test() {
console.log(i) // 依次输出:6 6 6 6 6
}, i * 1000);
}
闭包实现?
for (var i = 1; i <= 5; i++) {
(function (i) {
setTimeout(function () {
console.log('闭包:', i); // 依次输出:1 2 3 4 5
}, i * 1000);
}(i));
}
bind实现?
for (var i = 1; i <= 5; i++) {
// 缓存参数
setTimeout(function (i) {
console.log('bind', i) // 依次输出:1 2 3 4 5
}.bind(null, i), i * 1000);
}