js中call与apply用法

标签: chrome class Class function input prototype
36406人阅读 评论(7) 收藏 举报
分类:

前天去面试,有个gg问了一些js知识,其中有一道call与apply用法的题目,尽管在365天前用过call方法,但当时还是没能答上来,今天深入总结一下


call和apply,它们的作用都是将函数绑定到另外一个对象上去运行

两者的格式和参数定义:

call( thisArg [,arg1,arg2,… ] );       // 参数列表,arg1,arg2,...

apply(thisArg [,argArray] );                 // 参数数组,argArray

上面两个函数内部的this指针,都会被赋值为thisArg,这可实现将函数作为另外一个对象的方法运行的目的


一、call 的简单用法

首先,我们先看个简单的例子(call):

<!doctype html>

<html>
	<head>
		<title> call-apply </title>
	</head>

	<body>
		<input type="text" id="idTxt" value="input text">
		
		<script type="text/javascript">
			var value = "global var";
			
			function mFunc()
			{
				this.value = "member var";
			}
			
			function gFunc()
			{
				alert(this.value);
			}		
													
			window.gFunc();									// show gFunc, global var
			gFunc.call(window);								// show gFunc, global var
			gFunc.call(new mFunc());						// show mFunc, member var
			gFunc.call(document.getElementById('idTxt'));	// show element, input text
		</script>
		
		<script language="javascript">
			var func = new function()
			{
				this.a = "func";
			}
			
			var func2 = function(x)
			{
				var a = "func2";
				alert(this.a);				
				alert(x);
			}
			
			func2.call(func, "func2");						// show func and func2
		</script>
	</body>
</html>

然后,运行结果如下:

global var
global var
member var
input text
func
func2

测试环境:Google Chrome 10.0.648.45

最后,分析结果

1、全局对象window调用函数gFunc,this指向window对象,因此this.value为global var

2、函数gFunc调用call方法,this默认指向第一个参数window对象,因此this.value也为global var

3、函数gFunc调用call方法,this默认指向第一个参数new mFunc(),即mFunc的对象,因此this.value为mFunc的成员变量member var

4、函数gFunc调用call方法,this默认指向第一个参数input text控件,即id=‘idTxt’的控件,因此this.value为input控件的value值input text

5、函数func2调用call方法,this默认指向第一个参数func函数对象,因此this.value为this.a,即func

6、函数func2调用call方法,第二个参数属于函数对象func2的参数,因此alert(x)为第二个参数func2


二、call 继承用法与改进

js使用call模拟继承

测试代码:

<!doctype html>

<html>
	<head>
		<title> call - apply for inherit </title>
	</head>
	
	<body>
		<script type="text/javascript">
			function baseA()		// base Class A
			{
				this.member = "baseA member";
				this.showSelfA = function()
				{
					window.alert(this.member);
				}
			}
			
			function baseB()		// base Class B
			{
				this.member = "baseB member";
				this.showSelfB = function()
				{
					window.alert(this.member);
				}
			}
			
			function extendAB()		// Inherit Class from A and B
			{
				baseA.call(this);	// call for A
				baseB.call(this);	// call for B
			}
			
			window.onload = function()
			{
				var extend = new extendAB();	
				extend.showSelfA();		// show A
				extend.showSelfB();		// show B
			}
		</script>
	</body>
</html>
运行结果如下:

baseB member

baseB member

测试环境:Google Chrome 10.0.648.45

结果分析:

预期的结果,应该是输出 baseA member 和 baseB member,但实际输出却是 baseB member 和 baseB member

(已在IE9、8、6,Maxthon、Chrome、FF、Opera、Safari、360等浏览器测试过,结果都是后者:baseB member)

至此,机器是不会错的,这就需要我们深入分析

我们可能会很容易想到是this引起的,this两次都指向了baseB对象,但是推测真是这样吗?

为了探究实质,我们借助chrome浏览器的调试工具,下断点,进行调试,结果发现:


当调用extend.showSelfA();时,此时的this指向extendAB(并不是我们推测的两次都指向baseB对象

真实原因是extendAB对象的成员变量member在被baseB.call(this);实例化时,被baseB的成员member覆盖了,即extendAB的成员member由baseA member赋值成了baseB member

当然,我们也可以对上面baseA代码稍作修改,来验证我们调试分析的正确性:

function baseA() // base Class A
{
this.memberA = "baseA member";   // member改成memberA,以区分baseB中的member
this.showSelfA = function()
{
window.alert(this.memberA);    // 显示memberA
}
}

再次运行chrome等浏览器,结果如下:

baseA  member

baseB member

结果和我们的预期相同,同时chrome调试信息也验证了我们的正确性:




继承改进(prototype)

以上模拟继承方法,仔细分析不是最好的。

因为每次在函数(类)中定义了成员方法,都会导致实例有副本,因此可以借助prototype原型,进行改进

改进举例如下:

<!doctype html>

<html>
	<head>
		<title> call - apply for prototype </title>
	</head>
	
	<body>
		<script type="text/javascript">
			var Class = {
				create: function()				// create Function
				{
					return function()
					{
						this.initialize.apply(this, arguments);
					}
				}
			};
			
			var Person = Class.create();		// Create Class Person
			Person.prototype = {				// prototype initialize
				initialize: function(obj1, obj2)
				{
					this.obj1 = obj1;
					this.obj2 = obj2;
				},
				showSelf: function()
				{
					alert("obj: " + this.obj1 + " and " + this.obj2);
				}
			}
			
			// instance Class
			var person = new Person("man", "women");	// two params
			person.showSelf();							// show person
		</script>
	</body>
</html>
运行结果如下:
obj: man and women



查看评论

JS中的call()方法和apply()方法用法总结

JacvaScript中的call()方法和apply()方法, 1. 每个函数都包含两个非继承而来的方法:call()方法和apply()方法。 2. 相同点:这两个方法的作用是一样的。都是在特定的...
  • ganyingxie123456
  • ganyingxie123456
  • 2017-04-27 15:14:48
  • 42093

Js中的call方法

道听途说,一直以为Js是很弱智的,于是就没有学,直接进项目
  • whitewolf123
  • whitewolf123
  • 2014-06-10 17:29:28
  • 8408

JS的call方法的作用解释,简单易懂

先看看关于call()的官方解释,“调用一个对象的一个方法,以另一个对象替换当前对象。”,看了这样的解释,或许让你更摸不着头脑了。看例子: var x = "我是全局变量";    //定义...
  • ywl570717586
  • ywl570717586
  • 2016-09-27 15:49:15
  • 8125

js中的call()和apply()方法

1.call() 语法:obj1.call(obj2[,param1,param2,...]) 定义:用obj2对象来代替obj1,调用obj1的方法。即将obj1应用到obj2上。 说明:ca...
  • mafan121
  • mafan121
  • 2016-10-25 15:15:41
  • 5654

js (call()你不懂的)“继承的实现”

`一.对象冒充实现继承` 原理:让父类的构造函数成为子类的方法,然后调用该子类的方法,通过this关键字给所有的属性和方法赋值 优点:该种实现方式可以实现多继承 语法: func...
  • osdfhv
  • osdfhv
  • 2016-11-02 20:46:27
  • 1820

js的call() ,apply() 两种方法的区别和用法,最白话文的解释,让枯燥滚粗!

背景:今天群里有 妹子(我就不指名道姓喽)说:百度了一圈calll()函数和apply()函数,感觉还是糊里糊涂然后群里热闹了,各种表情包,各种殷勤,你懂的!正好我前几天刚又重新翻了一遍 那本 600...
  • xllily_11
  • xllily_11
  • 2016-05-23 13:17:08
  • 7541

Js apply 方法 详解

Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这...
  • qianzai5765638
  • qianzai5765638
  • 2011-11-09 14:24:39
  • 71683

Spring Cloud feign

实现系统之间的调用 SpringCloud Feign
  • wemlive
  • wemlive
  • 2017-02-08 10:43:09
  • 782

Spring Cloud Stream(消息驱动)

1、什么是Spring Cloud Stream Spring Cloud Stream 是一个用来为微服务应用构建消息驱动能力的框架。它可以基于Spring Boot 来创建独立的,可用于生产...
  • jack281706
  • jack281706
  • 2017-06-26 17:59:59
  • 5799

js中call和apply(函数的上下文调用模式)详解

上下文调用综述:     //上下文模式:根据用户传递的参数,指定了函数内部不同的this的值     //核心:以call/apply方法来调用某个函数     //cal...
  • ITzhongzi
  • ITzhongzi
  • 2017-03-09 09:11:31
  • 991
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 1243万+
    积分: 9万+
    排名: 15
    博客公告
    本博客内容,由米扑博客精心整理
    欢迎交流,欢迎转载,大家转载注明出处,禁止用于商业目的。

    博客专栏
    文章存档