初窥javascript奥秘之让人捉摸不定的this
http://www.xue5.com/WebDev/JavaScript/693311.html
之所以会有此篇文章当然还要从最近的一次面试说起,很抱歉居然又扯到面试上去看,其实不要说,平时不注意的东西,往往在面试时便会立马给你揪出来哪里有问题。
比如我当时就小小的栽了个跟头,栽跟头不要紧,要紧的是我确实对js的一些问题没有了解透彻。
俗话说的好,半灌水响叮当,我就那种一直认为自己js功底好的人,但真的拿出手来说,其实真的有点水了......此时再不好好学习一番,岂不是坐井观天,所以让我们开动吧!
小弟最近的文章基本都是边写边发,若是各位发现什么问题,或者感觉废话太多,请包涵。
闲扯作用域
你了解javascript的作用域吗?真的了解吗?那来试试这道题吧:
1 if (!("a" in window)) { 2 var a = 1; 3 } 4 alert(a);
好吧,拿出你的答案吧,吾已经露出了邪恶的笑容了,因为多数人看着这道题脑壳就有点昏(我会说我也有点昏吗???)
让我们一起来剥离她性感的外衣吧:
第一步:"a" in window这是什么意思?
意思是a是window的属性吗?那我们来做个试验:
我那个去,你会发现不管注释var a 还是不注释,a都是window的属性......于是上面答案呼之欲出!!!但我一团浆糊在我们脑袋中膨胀扩散......
在js的变量作用域中有个原则:所有变量声明都在范围作用域的顶部!
所以,之前我犯了一个愚蠢的错误,错的连我也吃惊,所以我把我自己喝大家都忽悠了,注意陷阱:
其实刚刚上面的完整代码是这样的:
<script type="text/javascript"> // var a; var in_window = 'a' in window; alert(in_window); if (!("a" in window)) { var a = 1; } alert(a); </script>
这样的话:in_window自然是true,这才是隐藏的真相!!!
若是注释下面这些代码的话:
终于正确了,刚刚因为自己的一个错误差点颠覆我最近学习的东西,太可怕了!
现在我们来看看“所有变量申明都会在范围作用域的顶部”是什么意思。
意思是在最下面定义的变量会自动提到上面去啦!!!所以我们定义变量时不如直接全部定义上去算啦。
回到本题:
if (!("a" in window)) { var a = 1; } alert(a);
其实他该是这个样子的。。。。
var a; if (!("a" in window)) { a = 1; } alert(a);
他将if里面的申明也提前了,怎么样不服气吧,其实我也是有点不服气,我想再试试:
var s = ''; if (false) { var a = 1; }
请注意,其中s没有任何意义,就是为了我方便设置断点:
至此真相出现,无论如何a的申明都会提前包括以下几种情况:
var s = ''; while (false) { var a = 1; }
变形一
学而不思则罔,我们将题目做个简单变形看看:
if (!("a" in window)) { a = 1; } alert(a);
在if里面去掉了申明,这道题就该是“1”了,但是若是if里面的代码不被执行的话就会报错了哟;
变形2:碰上了函数
刚刚那个现在看来就相对简单了,现在我们看看如此如此这般这般又会如何(我承认我闲的蛋疼好了)?
if (!("a" in window)) { var a = function () { window.a = 1; } } alert(a);
这样一改真的很蛋疼啦,这里不管a被定义为什么,但他是函数表达式,函数表达式就和原来一样,所以不变,if里面不会被执行!
那若是这个样子呢?
if (!("a" in window)) { function a() { window.a = 1; } } alert(a);
这个场景其实我也傻了,那么设置个断点看看:
看来a并不在window中,所以会执行if中的代码;
这里却又引出了另一个问题:到底变量提前或者函数提前?
var a = '1'; function a(){} alert(a);
function a() { } var a = '1'; alert(a);
这两种写法会导致最后输出有所不同吗???
答案是不会,他们的的结果都是1,原因就是函数式申明更加被优先啦,所以无论怎么写函数式什么都在最前面!!
function a() {return false; } if (a()) { var a = '1'; } s = ''; alert(a);
function a() {return true; } if (a()) { var a = '1'; } s = ''; alert(a);
我们前面说过,无论如何,if里面的申明会提前,那么我们这两道题可以改写一下:
var a = function () { return true }; var a; if (a()) { a = '1'; } s = ''; alert(a);
注意来:这里的10行,虽说申明了变量a却没有给其赋值,所以a还是函数,这从这里也可以看出来:
所以上面两个答案就没问题了,一个打印函数,一个打印数字1;
变形三
1 var a = 1, 2 b = function a(x) { x && b(--x); }; 3 alert(a);
现在我不运行代码试试是否可以解析,答案是不可以。。。我解析不出来,还是运行算了吧,我太水了!
这里涉及几个重要概念:
1 变量声明在进入执行上下文就完成了 2 函数声明也是提前的,所有的函数声明都在执行代码之前都已经完成了声明,和变量声明一样 3 函数声明会覆盖变量声明,但不会覆盖变量赋值,如我们上面看到的
想要理清问题,我还是老老实实一步步做工作吧:
根据规则三,这个结果是没有问题的,再看看下面的
从这里可以看出,若是注释了var a,这里function a()压根与它没什么事情,我们可以直接将之忽略(可能有误)
所以该题可以理解为:
var a = 1, b = function (x) { x && b(--x); }; alert(a);
坑爹的我本来是想对js中的this做次研究的,没想到在作用域相关的东西上转了这么久,但是经过这次折腾我相信在这块地方我应该不会出问题了吧???
进入正题
通常情况下, this代表的是前面提到的Globle Object,也就是Browser环境时的window Object.
当function作为某一对象的 method 时, this 代表这个 function 所属的 object