zoukankan      html  css  js  c++  java
  • js中call与apply用法

    js中call与apply用法

    前天去面试,有个gg问了一些js知识,其中有一道call与apply用法的题目,尽管在365天前用过call方法,但当时还是没能答上来,今天深入总结一下call和apply,它们的作用都是将函数绑定到另外一个对象上去运行

    两者的格式和参数定义:

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

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

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

     

    一、call 的简单用法

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

    1. <!doctype html>  
    2.   
    3. <html>  
    4.     <head>  
    5.         <title> call-apply </title>  
    6.     </head>  
    7.   
    8.     <body>  
    9.         <input type="text" id="idTxt" value="input text">  
    10.           
    11.         <script type="text/javascript">  
    12.             var value = "global var";  
    13.               
    14.             function mFunc()  
    15.             {  
    16.                 this.value = "member var";  
    17.             }  
    18.               
    19.             function gFunc()  
    20.             {  
    21.                 alert(this.value);  
    22.             }         
    23.                                                       
    24.             window.gFunc();                                 // show gFunc, global var  
    25.             gFunc.call(window);                             // show gFunc, global var  
    26.             gFunc.call(new mFunc());                        // show mFunc, member var  
    27.             gFunc.call(document.getElementById('idTxt'));   // show element, input text  
    28.         </script>  
    29.           
    30.         <script language="javascript">  
    31.             var func = new function()  
    32.             {  
    33.                 this.a = "func";  
    34.             }  
    35.               
    36.             var func2 = function(x)  
    37.             {  
    38.                 var a = "func2";  
    39.                 alert(this.a);                
    40.                 alert(x);  
    41.             }  
    42.               
    43.             func2.call(func, "func2");                      // show func and func2  
    44.         </script>  
    45.     </body>  
    46. </html>  
    <!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模拟继承

    测试代码:

    1. <!doctype html>  
    2.   
    3. <html>  
    4.     <head>  
    5.         <title> call - apply for inherit </title>  
    6.     </head>  
    7.       
    8.     <body>  
    9.         <script type="text/javascript">  
    10.             function baseA()        // base Class A  
    11.             {  
    12.                 this.member = "baseA member";  
    13.                 this.showSelfA = function()  
    14.                 {  
    15.                     window.alert(this.member);  
    16.                 }  
    17.             }  
    18.               
    19.             function baseB()        // base Class B  
    20.             {  
    21.                 this.member = "baseB member";  
    22.                 this.showSelfB = function()  
    23.                 {  
    24.                     window.alert(this.member);  
    25.                 }  
    26.             }  
    27.               
    28.             function extendAB()     // Inherit Class from A and B  
    29.             {  
    30.                 baseA.call(this);   // call for A  
    31.                 baseB.call(this);   // call for B  
    32.             }  
    33.               
    34.             window.onload = function()  
    35.             {  
    36.                 var extend = new extendAB();      
    37.                 extend.showSelfA();     // show A  
    38.                 extend.showSelfB();     // show B  
    39.             }  
    40.         </script>  
    41.     </body>  
    42. </html>  
    <!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原型,进行改进

    改进举例如下:

    1. <!doctype html>  
    2.   
    3. <html>  
    4.     <head>  
    5.         <title> call - apply for prototype </title>  
    6.     </head>  
    7.       
    8.     <body>  
    9.         <script type="text/javascript">  
    10.             var Class = {  
    11.                 create: function()              // create Function  
    12.                 {  
    13.                     return function()  
    14.                     {  
    15.                         this.initialize.apply(this, arguments);  
    16.                     }  
    17.                 }  
    18.             };  
    19.               
    20.             var Person = Class.create();        // Create Class Person  
    21.             Person.prototype = {                // prototype initialize  
    22.                 initialize: function(obj1, obj2)  
    23.                 {  
    24.                     this.obj1 = obj1;  
    25.                     this.obj2 = obj2;  
    26.                 },  
    27.                 showSelf: function()  
    28.                 {  
    29.                     alert("obj: " + this.obj1 + " and " + this.obj2);  
    30.                 }  
    31.             }  
    32.               
    33.             // instance Class  
    34.             var person = new Person("man", "women");    // two params  
    35.             person.showSelf();                          // show person  
    36.         </script>  
    37.     </body>  
    38. </html>  
    <!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
     
    来自:http://blog.csdn.net/sunboy_2050/article/details/6592082
  • 相关阅读:
    在CSS中,让页面里的字体变清晰,变细
    前端路由优缺点
    HBuilder和HBuilderX有什么区别?
    HTML5有哪些新特性,移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分HTML和HTML5?
    js中判断奇数或偶数
    遍历数组的方法
    数组的方法
    免费搜索引擎提交(登录)入口大全
    Vue.js详解
    简述JavaScript模块化编程(二)
  • 原文地址:https://www.cnblogs.com/lidj/p/3171360.html
Copyright © 2011-2022 走看看