有关javascript中的this

javascript中函数中的this的值取决于使用哪个对象调用这个函数;

function invocation in js is merely sending message between objects.

函数的调用者提供身份,而函数本身的实现提供在这个身份下的行为。函数的执行结果依赖于这个函数的调用者的身份,不同的函数的调用者,函数的输出是不同的。即使是js引擎内部的native方法也是这样。

值得注意的地方是,被调用的函数,有时是在由调用者的引用通过原型链查找所找到的在该对象的constructor.prototype这个对象中;除此以外,系统中还有几个地方有关this的规定,值得留意一下。

一个小例子

var s = Object.prototype.toString;
console.log(s()); //输出[object, window]

console.log(Object.prototype.toString()); //输出[object, Object]


 上例的前者调用toString方法是通过全局内的一个变量,该变量作为window的一个属性;而后者是Object.prototype这个对象的一个方法;

弄清由函数被调用时是由哪个对象引用着的

另一个例子:

var b = 10;
var a = {
    ab : function(){
        console.log(this);b--; //这里只有第一次输出[object, Object],后面9次都是[object, window]

        var c = arguments.callee, //注意保留arguments.callee的引用

        d = Array.prototype.slice.call(arguments);
        b >0 && setTimeout(arguments.callee, 0)
        //b > 0 && setTimeout(function(){ c.apply(a, d);}, 0); //如果使用这句则输出10次[object,Object], this指向a

    }
}
a.ab();

 

上例当中的arguments.callee被递归调用时,this为window;利用闭包的特性,可以使得其每次被系统调用时this仍指向a;

常常在程序运行时改变引用指向的对象,当这种情况时,需要理解真正引用着的对象是什么。例如下例。

function foo1(){
//some api functions
this.a = function(){alert(1);};
this.b = function{}{alert(2);};
}

function foo2(){
//some api functions
this.c = function(){alert(3);};
this.d = function(){alert(4);};
}

var a = new foo1();//2
foo1.prototype.extend = function(func){
   func.prototpye = a;
   a = new func();
   return this; //whom does this this refer to?
}

var b = a.extend(foo2);//1

alert(b.c); //what 's the output? can we visit the foo2's api function by using the reference b?

上例中,1处的a引用,指向2处new foo1所创建的那个对象,但extend方法在操作了原型链之后,让a指向了新的对象,通过更新后的a引用,可以通过原型链访问到a,b,c,d4种方法,但是extend方法中的this,却总是指向着这个方法被开始调用时的那个对象,即原来的a所引用着的2处的那个对象,若如上例返回this,则b实际上引用着原来2处创建的对象,alert(b.c)为undefined;

稍作修改可以让extend返回的对象成为继承着a和所传入的function对象的全部接口方法的新对象

foo1.prototype.extend = function(func){
    func.prototype = a;
    return new func;

弄清对象在被使用时的状态

出于某种原因,在并行下载的2段js当中,共同操作同一个命名空间或者同一个全局对象,其中一个js中的方法需要等待另一个js中对共同全局对象某些操作完成后才予以执行。我们可以通过labjs或者control js所介绍的方法去协调并行下载的js之中的依赖关系的问题,另外有关async属性和script异步下载与执行的问题可以参考这里和这里

我这里只是通过一个简单的wait函数(polling skill),利用浏览器对js代码的调度机制(这个可以阅读john resgn的这篇文章),来不断测试是否执行条件为true来调用目标函数,wait函数还提供了等待失败时对应的调用函数,这里要强调的是我们需要使用正确的引用。

<body>
<script type="text/javascript">

function add_a_script(url,async){
	var s = document.createElement("script");
	(async === true || async === "true" ) && (s.async = true);
	s.src = url;
	document.getElementsByTagName("head")[0].appendChild(s);
}

gloabl = {
	extend: function(func){
		func.prototype = global;
		return new func;
	}
}

add_a_script("http://some.url/2.js", true);
add_a_script("http://some.url/1.js");

</script>

</body>


1.js和2.js分别如下:

/* -- 1.js -- */
!function(g_var){
	g_var = g_var.extend(function(){
		this.wait = function(flag, callback, num, callback_final){
			flag + "_" + num in this || (this[flag + "_" + num] = num);
			var c = arguments.callee, d = arguments, that = this;
			var win_gv = window.global;
			_flag = win_gv.get_tag(flag); //use window.global rather than 'this'

			if (!_flag && this[flag + "_" + num] == 0) {
				typeof callback_final =="function" && callback_final.call(win_gv);
				return;
			}
			
			_flag ? callback.call(win_gv, _flag):(this[flag + "_" + num] > 0 && this[flag + "_" + num]--, setTimeout(function(){
				c.apply(that, Array.prototype.slice.call(d))
			}, 0));

		}

		this.get_tag = function(tag){
			return this[tag];
		}
	});
	window.global = g_var;
	
	g_var.wait("get_ready",function(flag){
		flag.call(this);
	}, 10, function(){
		alert("execute anyway!")
	});

}(window.global)

/* -- 2.js -- */
!function(g_var){
	alert(2);
	g_var = g_var.extend(function(){
		this.get_ready = function(){
			alert("flag ready!");
		}
	});
	window.global = g_var;
}(window.global)

 

上例中1.js和2.js的执行匿名函数,通过extend方法,在给global这个对象增加自己的api;当使用例子中的方法用add_a_script函数把1.js, 2.js添加到页面上,在支持async属性的浏览器中,2.js的执行会在1.js之后;wait函数,通过js的调度机制来递归执行自身,等待另一片js的执行给global增加的api方法,特别值得注意的是,通过get_tag方法获取所等待的函数饮用水时,要使用window.global这个变量,而不是this。如前面所说的,函数中this的这个值,总是固执的指向着这个函数的在开始被调用时的那个调用者对象,在经过另外一片(2.js)的执行之后,这个this所引用着的对象已经是global的__proto__隐藏属性所引用的那个prototype对象了;因此,要注意,要想取到被等待的函数引用,应该使用正确的引用 - global;

注意加入脚本的方式和async属性的作用;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值