Javascript中call的使用
Javascript中call的使用自己感觉蛮纠结的,根据文档很好理解,其实很难确定你是否真正的理解。
call 方法
应用于:Function 对象
调用一个对象的一个方法,以另一个对象替换当前对象。
call([thisObj[,arg1[, arg2[, [,.argN]]]]])
参数:
thisObj
可选项。将被用作当前对象的对象。
arg1, arg2, , argN
可选项。将被传递方法参数序列。
说明:
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。
1.最基本的理解:示例1
自定义一个类,该类有一个方法showTxt,用来显示当前对象的name值。
创建一个对象,并且该对象的name值等于test1。
使用call方法,使新创建的对象obj添加Class1类的showTxt方法,即把Class1类中的this.showTxt中的this指定成obj,这样obj就有了showTxt方法。弹出"test1"。
this.showTxt = function(){alert(this.name)}
}
var obj = new Object();
obj.name="test1"
Class1.call(obj);
obj.showTxt();//test1
alert(obj.showTxt);//function(){alert(this.name)}
这个例子很容易理解。
2.再看一个稍微深入的理解
示例2:创建Class1的实例,让这个实例调用showTxt方法返回这个实例的name值,因为这个实现没有name值所以返回undefine.
this.showTxt = function(){alert(this.name)}
}
var class1 = new Class1();
class1.showTxt();//undefined
alert(class1.showTxt);//function(){alert(this.name)}
示例3:下面就给Class1添加个name值,这时class1再调用showTxt方法,会返回class1,这是因为给类添加了name值,所以实例的name也由undefine变成了class1.
this.name = 'class1';//添加name值
this.showTxt = function(){alert(this.name)}
}
var class1 = new Class1();
class1.showTxt();//class1
alert(class1.showTxt);//function(){alert(this.name)}
示例4:Class1.call(obj) 这个操作把Class1中的this.name,this.showTxt里的this替换成了obj,所以就变成了obj.name='class1',所以obj.showTxt在执行时返回class1。
this.name = 'class1';//添加name值
this.showTxt = function(){alert(this.name)}
}
function Class2(){
this.name = 'class2';
}
var class2 = new Class2();
Class1.call(class2);
alert(class2.showTxt);//function(){alert(this.name)}
class2.showTxt();//class1
示例5:如果在Class1.call(obj);之后再添加obj.name = 'test1',最后结果会输入test1,原因显而易见。
this.name = 'class1';//添加name值
this.showTxt = function(){alert(this.name)}
}
function Class2(){
this.name = 'class2';
}
var class2 = new Class2();
Class1.call(class2);
class2.name = 'test1';//重定义obj.name值
alert(class2.showTxt);//function(){alert(this.name)}
class2.showTxt();//test1
上面的例子call的都是一个对象的实例,接下来的案例把对象的实例直接换成函数,看看执行结果会发生哪些变化
3.把call方法的第一参数由实例换成函数看看会怎么
示例6:Class2是一个function对象的引用,在执行Class1.call(Class2)时this.showTxt里的this被替换成了Class2。这样Class2就有了showTxt方法,Class2.showTxt()执行时会返回Class2.name的值,因为Class2并未定义name值,所以会返回undefined。
Class2函数里的this.name是由Class2创建实例的name值,并不是Class2.name,这两个值有时会让我迷糊。
this.showTxt = function(){alert(this.name)}
}
function Class2(){
this.name = 'class2';
}
Class1.call(Class2);
alert(Class2.showTxt);//function(){alert(this.name)}
Class2.showTxt();//undefined
4.接着看下面的例子
示例7:class1.showTxt.call(class2);之所以会返回class2是因为function(){alert(this.name)}这里的this被call指定成了class2,变成了alert(class2.name),所以会返回class2.
alert(class2.showTxt)返回undefined,说明并未定义class2.showTxt方法。
this.showTxt = function(){alert(this.name)}
}
function Class2(){
this.name = 'class2';
}
var class1 = new Class1();
var class2 = new Class2();
class1.showTxt.call(class2);//class2
alert(class2.showTxt);//undefined
因为并为给class2添加showTxt方法,所以提示该错误。如果在这个调用之前添加Class1.call(class2);这个调用就OK了
class2.showTxt();//class1
示例8:这个例子都会返回undefined
this.showTxt = function(){alert(this.name)}
}
function Class2(){
this.name = 'class2';
}
var class1 = new Class1();
class1.showTxt.call(Class2);//undefined
alert(Class2.showTxt);//undefined
5.在使用call时如果调用函数里没有this会怎么样
示例9:
alert(a+b);
}
function sub(a,b){
alert(a-b);
}
add.call(sub,3,1);//4
结果返回4,add.call(sub,3,1)在执行过程中,sub做为add函数中this的替代品出现,但是因为add里没有用到this,所以sub函数直接忽略,所以结果是4。
所以实际执行如下:返回4。
alert(a+b);
}
add(3,1);//4
6.不错,接下来再理解一个怪异的形式
示例10:
alert(1);
}
function f2(){
alert(2)
}
var f3 = f1.call;
f1.call(f2);//1
f3.call(f2);//2
f1.call(f2);比较好理解,如果不理解看上边的case,但如何理解f3.call(f2)会返回2呢,为了方便理解进行一下等效变化为f1.call.call(f2),这时会发现实际上是f1.call方法call调用了f2,那f1怎么又会有call方法呢?call, apply都属于Function.prototype的一个方法,它是JavaScript引擎内在实现的,因为属于Function.prototype,所以每个Function对象实例,也就是每个方法都有call, apply属性。
在理解f1.call.call(f2)时我们首先要知道call方法到底是如何执行的,这样才能f1.call.call(f2)如何执行。
示例11:
引用JK写的一个用apply实现call的方法:
var argsNew = [];
for(var i=1;i<arguments.length;i++){
argsNew.push(arguments[i]);
}
return this.apply(oThis,argsNew);
}
Function.prototype.jsCall = jsCall;
或简写成
var argsNew = [].slice.call(arguments,1)
return this.apply(oThis,argsNew);
}
Function.prototype.jsCall = jsCall;
这样就得到了一个和call一样功能的jsCall.
接下来构建两个函数f1,f2
alert([this,a,'f1']);
}
f1(11);//[object Window],11,f1
function f2(a){
alert([this,a,'f2']);
}
f2(22);//[object Window],11,f2
用jsCall把f1中的this替换成f2
alert([this,a,'f1']);
}
function f2(a){
alert([this,a,'f2']);
}
f1.jsCall(f2,11);//function f2(a){alert([this, a, "f2"]);},11,f1
执行结果发现[object Window]被替换成f2函数
var argsNew = [].slice.call(arguments,1)
return this.apply(oThis,argsNew);
}
Function.prototype.jsCall = jsCall;
function f1(a){
alert([this,a,'f1']);
}
function f2(a){
alert([this,a,'f2']);
}
f1.jsCall.jsCall(f2,11);//11,,f2
在执行f1.jsCall.jsCall(f2,11);时返回11,,f2,为什么会返回这个结果,重点来了:)
f1.jsCall方法:
//返回
//function jsCall(oThis) {
// var argsNew = [].slice.call(arguments, 1);
// return this.apply(oThis, argsNew);
//}
所以f1.jsCall.jsCall可以替换成jsCall.jsCall看一下执行结果
var argsNew = [].slice.call(arguments,1)
return this.apply(oThis,argsNew);
}
Function.prototype.jsCall = jsCall;
function f1(a){
alert([this,a,'f1']);
}
function f2(a){
alert([this,a,'f2']);
}
jsCall.jsCall(f2,11);//11,,f2
接着分析
jsCall在执行的过程中,return this.apply(oThis,argsNew);里的this被替换成了f2,11做为参数传给了(oThis,argsNew),变成了f2.apply(11);
var argsNew = [].slice.call(arguments,1)
return this.apply(oThis,argsNew);
}
Function.prototype.jsCall = jsCall;
function f1(a){
alert([this,a,'f1']);
}
function f2(a){
alert([this,a,'f2']);
}
f2.apply(11);//11,,f2
返回结果跟f1.jsCall.jsCall(f2,11)一样。
回过头来看
alert(1);
}
function f2(){
alert(2)
}
var f3 = f1.call;
f1.call(f2);//1
f3.call(f2);//2
这样就不难理解f1.call.call(f2)实现时,f1.call执行过程中call中的this被f2替换成了f2.call();因为f2里没有this的引用所以执行结果是2.
需要十分注意的是f1.call是方法,f1是函数对象,这两者在call时是有区别的。
转载于:https://www.cnblogs.com/guopei/archive/2011/04/17/2019045.html
Javascript中call的使用相关推荐
- 浅析 JavaScript 中的 函数 uncurrying 反柯里化
柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...
- JavaScript中,this的绑定规则
对于 JavaScript 新手来说,this 是非常基础同时也难以理解的知识点. 比如下面的代码,this 指向就有三种方式. 在<你不知道的 JavaScript>一书中,我总算比较清 ...
- Javascript中undefined,NaN等特殊比较
以下内容转自: http://blog.csdn.net/hongweigg/article/details/38090093 1.问题:在Javascript中,typeof(undefined) ...
- Javascript中二进制数据处理方法
Javascript中二进制数据处理方法 转载于:https://www.cnblogs.com/motadou/archive/2012/02/19/2358514.html
- JavaScript 中的有限状态机
http://www.ibm.com/developerworks/cn/web/wa-finitemach/ JavaScript 中的有限状态机 Page navigation 系列文章 有限状态 ...
- 在Javascript中使用面向对象的编程
by Mike Koss March 26th, 2003 这是一篇,我个人认为最好的,Javascript面向对象编程的文章.翻译不好的地方,还望大家指正,谢谢. 如果您需要,可以访问下面的地址取得 ...
- 取出url中的字符_如何在JavaScript中解析URL:例如主机名,路径名,查询,哈希?...
统一资源定位符(缩写URL)是对Web资源(网页,图像,文件)的引用.URL指定资源位置和检索资源的机制(http,ftp,mailto). 例如,这是此博客文章的URL: 通常,您需要访问URL的特 ...
- 在javascript中判断类型
String 一个字符串始终是一个字符串,所以这一块是很容易.除非使用new(new String)调用,否则typeof将返回"object".所以也要包含那些可以使用的字符串i ...
- JavaScript中几个重要的知识点(1) ---- 面向对象
JavaScript中几个最重要的大知识点 面向对象 DOM事件 异步交互ajax 面向对象 在JS中可以把任意的引用和变量都看成是一个对象.面向对象的主要三个表现形式: 封装 继承 多态 1. 封装 ...
- javascript中实例方法与类方法的区别
在javascript中,类有静态属性和实例属性之分,也有静态方法和实例方法之分 类属性(静态属性):通过类直接访问,不需要声明类的实例来访问 类方法(静态方法):通过类直接访问,不需要声明类的实例来 ...
最新文章
- CharSequence和String的区别
- nginx常见面试题
- 以股票RSI指标为例,学习Python发送邮件功能(含RSI指标确定卖点策略)
- Eclipse里不同的project,右键选择属性property facet里看到的list 内容是否相同
- 我的世界服务器无限装备指令2020,我的世界区域保护指令_我的世界区域保护指令除了自己手机版刷屏2020_攻略...
- CSS属性选择器温故-4
- LeetCode 1497. 检查数组对是否可以被 k 整除(余数配对)
- 洛谷 P3258 [JLOI2014]松鼠的新家 解题报告
- [转载] 动态口令,动态密码生成(OTP)
- 钩子教程 - 原理(二十五) : 消息 -- WM_CANCELJOURNAL
- 用c#开发微信(10) JSSDK 基本用法 分享接口“发送到朋友”
- c语言编译器masm,汇编环境搭建 -- MASM32
- flink-metric原理与实战
- matlab 跳步,给定两个大整数u和v,它们分别有m和n位数字,且m≤n.用通常的乘法求uv的值需要O(mn)时间.可以将u和v.. - 上学吧找答案(手机版)...
- Android 消息通知栏用法详解(一)
- python统计汉字个数是_Python入门(一):一句话统计文章不重复汉字数
- npm安装任何包都报错解决方法
- 阿里云Centos7服务器域名解析和Nginx配置
- 内核辅助函数系列 001 --- __ffs(unsigned long word):第一个非 0 位
- 使用aireplay-ng抓握手包笔记
热门文章
- Linux vim打开文件的四种方式
- Spring4 MVC表单验证代码示例
- SQL 语句之insert语句插入数据:若表中有重复的主键或数据继续插入解决方案
- java set path_Java Path.setEffect方法代码示例
- 造轮子是什么意思_程序员发文质疑阿里天启为kpi项目,重复造轮子,阿里回应:诽谤...
- centos7设置时间为日本东京时间
- python如何小写p转换p_Python如何将字符串“p”从列表转换为变量值p
- Oracle 原理: 视图,对视图进行增删改操作
- 编译实验(一)词法分析
- Linux CPU数、物理核、逻辑核的查看方法及线程进程的绑定方法