初窥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的属性吗?那我们来做个试验:

初窥javascript奥秘之让人捉摸不定的this

初窥javascript奥秘之让人捉摸不定的this

我那个去,你会发现不管注释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,这才是隐藏的真相!!!
初窥javascript奥秘之让人捉摸不定的this

若是注释下面这些代码的话:

初窥javascript奥秘之让人捉摸不定的this

终于正确了,刚刚因为自己的一个错误差点颠覆我最近学习的东西,太可怕了!

现在我们来看看“所有变量申明都会在范围作用域的顶部”是什么意思。

初窥javascript奥秘之让人捉摸不定的this

意思是在最下面定义的变量会自动提到上面去啦!!!所以我们定义变量时不如直接全部定义上去算啦。

回到本题:

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没有任何意义,就是为了我方便设置断点:
初窥javascript奥秘之让人捉摸不定的this

至此真相出现,无论如何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);

这个场景其实我也傻了,那么设置个断点看看:
初窥javascript奥秘之让人捉摸不定的this

看来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);

初窥javascript奥秘之让人捉摸不定的this

注意来:这里的10行,虽说申明了变量a却没有给其赋值,所以a还是函数,这从这里也可以看出来:

初窥javascript奥秘之让人捉摸不定的this

所以上面两个答案就没问题了,一个打印函数,一个打印数字1;

变形三

1 var a = 1,
2 b = function a(x) { x && b(--x); }; 
3 alert(a);

现在我不运行代码试试是否可以解析,答案是不可以。。。我解析不出来,还是运行算了吧,我太水了!
这里涉及几个重要概念

1 变量声明在进入执行上下文就完成了
2 函数声明也是提前的,所有的函数声明都在执行代码之前都已经完成了声明,和变量声明一样
3 函数声明会覆盖变量声明,但不会覆盖变量赋值,如我们上面看到的

想要理清问题,我还是老老实实一步步做工作吧:

初窥javascript奥秘之让人捉摸不定的this

根据规则三,这个结果是没有问题的,再看看下面的

初窥javascript奥秘之让人捉摸不定的this

 初窥javascript奥秘之让人捉摸不定的this

从这里可以看出,若是注释了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

相关推荐