摘要:剩下的两个,我们分别改变了他们的执行环境,分别指向了和,于是结果就是显示对象各自的值。如果你仍然对和没有清晰的认识,可以试着这样理解。
在Javascript中,每个函数都包含两个非继承而来的方法,call和apply。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内的this对象的值。
摘自《JavaScript高级程序设计》
apply方法接收两个参数,第一个参数是在其中运行函数的作用域,第二个是一个参数数组或者arguments对象。
call方法与apply方法作用相同,第一个参数也相同,区别在于,其余的参数需要逐个列出。
apply(thisArg, argArray); call(thisArg[,arg1,arg2…]);
是使用call还是apply要看具体的情况。如果你知道所有参数或者参数的数量不多,可以使用call;如果参数的数量不确定,或者数量很大,或者你收到的是一个数组或者是个arguments对象,则需要使用apply。
下面是使用apply的一些典型例子
// 获得数组中最大的元素 var arr = [1, 8, 10, 3, 24, 89, 26]; var m = Math.max.apply(Math, arr); // m => 89 // 将类数组的对象转为数组 var arr = Array.prototype.slice.call(arguments);
事实上,call和apply真正的用武之地在于,他们能够扩充函数赖以运行的作用域。
我们再来看下面的例子
var name = "out" var o1 = { name: "hello" }; var o2 = { name: "world" }; function sayName() { alert(this.name); } sayName.call(this); // out sayName.call(window); // out sayName.call(o1); // hello sayName.call(o2); // world
前两个输出相同,因为在全局作用域,this即为window(浏览器环境)。
剩下的两个,我们分别改变了他们的执行环境,分别指向了o1和o2,于是结果就是显示对象各自的name值。
那么,使用call和apply有什么好处呢?我们发现,同样的一个函数,当指定不同的执行环境时,会产生不同的结果,这么做的一个最大的好处就是解耦。
使用call和apply,函数和对象没有强依赖关系,多个对象可以使用同一个函数,避免了资源的浪费,同时对于模块化编程也大有帮助。
如果你仍然对call和apply没有清晰的认识,可以试着这样理解。
我们把方法比作是工具,比如一把刀;而变量是具体的实物,比如一个苹果。我们可以使用这把刀切很多不同的苹果,在切苹果的过程中,实际上就是改变了刀的作用对象---不同的苹果。
在上面的例子
// 将类数组的对象转为数组 var arr = Array.prototype.slice.call(arguments);
slice是一个方法,但是它是属于Array对象prototype属性所有的,在对arguments使用时,我们可以理解为借用。
比如张三会砍树,即张三有砍树这个方法(至于张三有没有树无所谓),而李四有树,但他却不会砍,这时李四便可以借用张三砍树的方法来砍自己的树,写成代码就是
var zhangsan = { cut: function() { alert(this.tree); } }; var lisi = { tree: "杨树" }; zhangsan.cut.call(lisi); // alert("杨树")
还有一种情况是,李四自己也会砍树,但是有一天他病了,砍不动了,这时他也可以借用张三的砍树方法砍自己的树。在代码中就是
String.prototype.toString = function() { return "shit"; // 所有的String的实例对象的toString方法都被污染了,只会输出"shit" }; var str = "hello"; console.log(str.toString()); // "shit" // 这时候怎么办呢? // 我们需要找一个没被污染的toString方法借来用一用,比如Object(或者Array等除了String的都可以) console.log(Object.prototype.toString.call(str)); // 输出正常的"[object String]"
到了这里,相信你对call和apply已经有了一个比较形象的认识了。以后再遇到类似的问题时,不妨想象成现实中的关系,可能困扰许久的问题就豁然开朗了。
call和apply另外一个应用就是函数的柯里化和反柯里化技术,有兴趣的可以看下面两篇文章
Javascript中有趣的反柯里化技术
由JavaScript反柯里化所想到的
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/87568.html
摘要:理解文章中已经比较全面的分析了在中的指向问题,用一句话来总结就是的指向一定是在执行时决定的,指向被调用函数的对象。与和直接执行原函数不同的是,返回的是一个新函数。这个新函数包裹了原函数,并且绑定了的指向为传入的。 理解 JavaScript this 文章中已经比较全面的分析了 this 在 JavaScript 中的指向问题,用一句话来总结就是:this 的指向一定是在执行时决定的,...
摘要:可能上面的例子不是很常见,但是我们经常见到这样的代码你好美女你好美女方法是数组特有的方法,它是定义在构造函数的原型中的方法,所以我们实例化的数组就都继承了这个方法,但是字符串是没有方法,但此处我们就借用了数组的方法来处理字符串。 在学习javascript的时候,对于call()和apply()的用法总是难以理解,相信很多小伙伴和我又一样的想法。现在和小伙伴们分享一下。 call ...
摘要:,,和都是用来改变函数执行时的上下文也就是说改变的指向问题,是的方法,引入是因为没有将设置成行参。一般都是库里面用不推荐自己使用和。和唯一区别是参数不一样,是的语法糖是返回一个新函数供以后调用,相比其他两个比较常用。而和是立即调用。 apply(),call(),和bind()都是用来改变函数执行时的上下文也就是说改变this的指向问题,是prototype的方法,引入是因为js没有将...
摘要:输出的作用与和一样,都是可以改变函数运行时上下文,区别是和在调用函数之后会立即执行,而方法调用并改变函数运行时上下文后,返回一个新的函数,供我们需要时再调用。 前言 js中的call(), apply()和bind()是Function.prototype下的方法,都是用于改变函数运行时上下文,最终的返回值是你调用的方法的返回值,若该方法没有返回值,则返回undefined。这几个方法...
摘要:在全局对象中调用,自然读取的是全局对象的值构造器调用说明作为构造器调用时,指向返回的这个对象。最直观的表现就是,去看一些优秀框架的源代码时,不再是被绕的晕乎乎的。 学习起因: 在之前的JavaScript学习中,this,call,apply总是让我感到迷惑,但是他们的运用又非常的广泛。遂专门花了一天,来弄懂JavaScript的this,call,apply。中途参考的书籍也很多,以...
阅读 849·2021-11-22 09:34
阅读 931·2021-10-08 10:16
阅读 1753·2021-07-25 21:42
阅读 1776·2019-08-30 15:53
阅读 3488·2019-08-30 13:08
阅读 2128·2019-08-29 17:30
阅读 3258·2019-08-29 17:22
阅读 2154·2019-08-29 15:35