`
zccst
  • 浏览: 3322363 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JS-call和apply(一)

阅读更多
作者:zccst

2014-6-10
昨天对Array.prototype.slice.call(arguments);还是不太理解,不知道为什么slice调用时,可以将arguments切为数组。

今天理解call(this, args);中的this是一个对象。而不是一个函数function(){}。
var test1 = {
	age : 10,
	sum : function(){
		return this.age;
	}
}
console.log(Array.prototype.slice.call(test1));//打印[]


function test2(){
	this.age = 10;
	this.sum =function(){
		return this.age;
	}
}
console.log(Array.prototype.slice.call(test2));//打印[]


var test3 = {
	0 : 10,
	1 : function(){
		return this[0];
	},
	length:2
}
console.log(Array.prototype.slice.call(test3));//将类数组对象转换成真正的数组


/**/
function Product(name, price) {
  this.name = name;
  this.price = price;

  if (price < 0)
    throw RangeError('Cannot create product "' + name + '" with a negative price');
  return this;
}

function Food(name, price) {
  console.log(this);//打印?
  Product.call(this, name, price);
  this.category = 'food';
}
Food.prototype = Object.create(Product.prototype);

function Toy(name, price) {
  console.log(this);//打印?
  Product.call(this, name, price);
  this.category = 'toy';
}
Toy.prototype = Object.create(Product.prototype);

var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);
//console.log(cheese);
//console.log(fun);





2014-6-9
重新看以前call的文章,觉得call应该就是指定某一个函数在某一个作用域中执行。
比如:Array.prototype.slice.call(arguments);
jquery的proxy的实现
proxy: function( fn, context ) {
		var tmp, args, proxy;

		if ( typeof context === "string" ) {
			tmp = fn[ context ];
			context = fn;
			fn = tmp;
		}

		// Quick check to determine if target is callable, in the spec
		// this throws a TypeError, but we will just return undefined.
		if ( !jQuery.isFunction( fn ) ) {
			return undefined;
		}

		// Simulated bind
		args = core_slice.call( arguments, 2 );
		proxy = function() {
			return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
		};

		// Set the guid of unique handler to the same of original handler, so it can be removed
		proxy.guid = fn.guid = fn.guid || jQuery.guid++;

		return proxy;
	}







2013-8-21
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
			/*相当于
			var Person = function(){
				this.initialize.apply(this, arguments);
			}
			*/
			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
分享到:
评论

相关推荐

    JavaScript中call与apply方法

    JavaScript中call与apply方法

    关于Javascript中call与apply的进一步探讨

    在JavaScript中,`call`和`apply`是两个非常重要的方法,它们都用于改变函数调用时的上下文(即`this`的值),并且可以灵活地传递参数。本篇文章将深入探讨这两个方法的用法、区别以及实际应用场景。 `call`方法...

    js-object-oriented-bind-call-apply-readme-v-000

    在这段代码中,我们将练习bind , call和apply 。 您可以使用浏览器的JS控制台进行跟踪,也可以使用httpserver来提供所提供的index.html 。 HTML文件将自动加载index.js并在浏览器中显示您所做的编辑。 目标 使用...

    js代码-call 和 apply 以及bind 的用途

    在JavaScript中,`call`、`apply`和`bind`都是与函数调用相关的三个重要方法,它们都允许我们改变函数执行时的上下文(即`this`关键字指向的对象)和参数传递。这三个方法在实际编程中有着广泛的应用,帮助开发者...

    Javascript - 全面理解 caller,callee,call,apply (转载)

    这篇文章将深入探讨四个关键概念:caller、callee、call和apply,它们都是JavaScript函数操作的核心部分,对于理解和使用高级JavaScript编程至关重要。 首先,我们来了解`caller`和`callee`。在JavaScript的函数...

    arguments-call-apply.rar_Windows编程_Java_

    在这个"arguments-call-apply.rar"压缩包中,我们似乎找到了一个关于JavaScript函数调用模式的学习资源,特别是`arguments`对象以及`call`和`apply`方法的使用,这在JavaScript中是非常基础且关键的知识点。...

    js中call与apply的用法小结

    在JavaScript中,`call` 和 `apply` 是两种非常重要的函数调用方式,它们都用于改变函数执行时的上下文,即`this`的指向。本文将深入探讨这两种方法的用法及其在实际编程中的应用。 ### 1. `call` 的基本用法 `...

    js-object-oriented-bind-call-apply-this-lab-nyc-web-051418

    绑定,致电,申请实验室目标使用JavaScript的绑定,调用和应用方法来更改函数的范围并正确传递参数指示在本实验中,我们的测试定义了一些函数,然后将这些函数传递给我们要求您编写的函数。 您的函数不仅应调用作为...

    理解JavaScript的caller callee call apply

    ### 理解JavaScript中的`caller`...综上所述,理解`caller`、`callee`、`call`、`apply`以及`arguments`对象在JavaScript编程中至关重要,它们不仅增强了函数的灵活性和复用性,还提供了深入分析和调试代码的强大工具。

    js代码-call、apply、bind

    在JavaScript中,`call()`, `apply()`, 和 `bind()` 都是Function对象的方法,它们都用于改变函数调用时的上下文(即`this`关键字指向的对象),以及动态地传入参数。理解这三个方法对于深入掌握JavaScript的面向...

    js-object-oriented-bind-call-apply-this-lab-dumbo-web-042318

    绑定,致电,申请实验室目标使用JavaScript的绑定,调用和应用方法来更改函数的范围并正确传递参数指示在本实验中,我们的测试定义了一些函数,然后将这些函数传递给我们要求您编写的函数。 您的函数不仅应调用作为...

    Js的call与apply1

    `call`和`apply`的另一个重要应用是实现JavaScript中的继承。由于JavaScript采用原型链实现继承,我们可以利用这两个方法将父类的构造函数执行上下文绑定到子类实例上: ```javascript function Animal(name, ...

    详解js中call与apply关键字的作用.docx

    JavaScript中的`call`和`apply`是两种非常重要的方法,它们都用于改变函数内部`this`的指向,并执行该函数。这两个方法都是Function对象的原型方法,因此所有的函数都具备`call`和`apply`。 1. `call`方法: - `...

    Javascript - 全面理解 caller,callee,call,apply

    在JavaScript的世界里,caller、callee、call和apply是四个非常重要的概念,它们涉及到函数的调用方式和执行上下文。这些知识点对于深入理解和优化代码至关重要,尤其在处理高阶函数和面向对象编程时。 首先,让...

    javascript中call和apply方法浅谈

    当`call`和`apply`的第一个参数为`null`或`undefined`时,`this`将默认指向全局对象(在浏览器环境中是`window`,在Node.js环境中是`global`)。例如: ```javascript var a = 10, b = 20; function testFun() { ...

    详解js中call与apply关键字的作用

    在JavaScript中,call与apply是两个非常...call和apply在JavaScript中的运用广泛且灵活,无论是改变函数上下文还是借用其他对象的方法,它们都能起到很大的作用。掌握这两者,可以让你的JavaScript编程更加高效和优雅。

    JavaScript中call和apply方法的区别实例分析

    本文实例分析了JavaScript中call和apply方法的区别。分享给大家供大家参考,具体如下: 这两个方法不经常用,但是在某些特殊场合中是非常有用的,下面主要说下它们的区别: 1、首先,JavaScript是一门面向对象的语言...

    javascript中apply和call方法的作用及区别说明

    一、call和apply的说明 1、call,apply都属于Function.prototype的一个方法,它是JavaScript引擎内在实现的,因为属于Function.prototype,所以每个Function对象实例(就是每个方法)都有call,apply属性。既然作为...

Global site tag (gtag.js) - Google Analytics