当调用一个函数时,可以赋值一个不同的 this 对象。this 引用当前对象,即 call 方法的第一个参数。通过 call 方法,你可以在一个对象上借用另一个对象上的方法,比如Object.prototype.toString.call([]),就是一个Array对象借用了Object对象上的方法。
作用:
使用call方法调用父构造函数
使用call方法调用匿名函数
使用call方法调用匿名函数并且指定上下文的'this'
这里插个题外话:
apply 与 call() 非常相似,不同之处在于提供参数的方式。apply 使用参数数组而不是一组参数列表。apply 可以使用数组字面量(array literal),如 fun.apply(this, ['eat', 'bananas']),或数组对象, 如 fun.apply(this, new Array('eat', 'bananas'))。你也可以使用 arguments 对象作为 argsArray 参数。 arguments 是一个函数的局部变量。 它可以被用作被调用对象的所有未指定的参数。 这样,你在使用apply函数的时候就不需要知道被调用对象的所有参数。 你可以使用arguments来把所有的参数传递给被调用对象。 被调用对象接下来就负责处理这些参数。
从 ECMAScript 第5版开始,可以使用任何种类的类数组对象,就是说只要有一个 length 属性和[0...length) 范围的整数属性。例如现在可以使用 NodeList 或一个自己定义的类似 {'length': 2, '0': 'eat', '1': 'bananas'} 形式的对象。
call, apply方法区别是,从第二个参数起, call方法参数将依次传递给借用的方法作参数, 而apply 直接将这些参数放到一个数组中再传递, 最后借用方法的参数列表是一样的.
应用场景:当参数明确时可用call, 当参数不明确时可用apply给合arguments
现在先给出一个例子
总所皆知,onscolll,onresize等是非常耗性能,窗口缩放时打印数字。
var count = ; window.onresize = function () { count++; console.log(count); }
在chrome浏览器中伸缩浏览器窗口大小,打印如下
这显然不是我们想要的,那如果我们换成ajax请求的话,那么就会缩放一次窗口会连续触发多次ajax请求,下面我们试着使用函数节流的操作试试一下;当然加个settimeout()的定时器就好了,
第一种封装方法
var count = ; function oCount() { count++; console.log(count); } window.onresize = function () { delayFun(oCount) }; function delayFun(method, thisArg) { clearTimeout(method.props); method.props = setTimeout(function () { method.call(thisArg) }, ) }
第二种封装方法
构造一个闭包,使用闭包的方式形成一个私有的作用域来存放定时器timer, timer是通过传参数的形式引入的。
var count = ; function oCount() { count++; console.log(count); } var funs= delayFun(oCount,); window.onresize = function () { funs() }; function delayFun(func, wait) { var timer = null; return function () { var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function () { func.apply(context, args); }, wait) }; }
对第二种方法优化一下,性能会更好
这里返回一个函数,如果它被不间断地调用,它将不会得到执行。该函数在停止调用 N 毫秒后,再次调用它才会得到执行。如果有传递 ‘immediate' 参数,会马上将函数安排到执行队列中,而不会延迟。
function delayFun (func, wait, immediate) { var timeout; return function() { var context = this, args = arguments; var later = function() { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }; // 用法 var myEfficientFn = delayFun (function() { // 所有繁重的操作 }, ); window.addEventListener('resize', myEfficientFn);
函数不允许回调函数在指定时间内执行多于一次。当为一个会频繁触发的事件分配一个回调函数时,该函数显得尤为重要。
setTimeout这么厉害,那么我们是可以在项目中大量使用吗?
我个人是不建议的,在我们业务中,基本上是禁止在业务逻辑中使用setTimeout的,因为我所看到的很多使用方式都是一些问题好解决,setTimeout作为一个hack的方式。
例如,当一个实例还没有初始化的前,我们就使用这个实例,错误的解决办法是使用实例时加个setTimeout,确保实例先初始化。
为什么错误?这里其实就是使用hack的手段
第一是埋下了坑,打乱模块的生命周期
第二是出现问题时,setTimeout其实是很难调试的。
我认为正确的使用方式是,看看生命周期(可参考《关于软件的生命周期 》),把实例化提到使用前执行。
有关JS中setTimeout的巧妙用法前端函数节流,小编就给大家介绍到这里,希望对大家有所帮助!
您可能感兴趣的文章: