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

javascript疑难解答

阅读更多
前段时间去听了一个同事的knowledge share session,他大致给我们讲了一些写javascript需要注意的一些细节。session本身并没有什么问题,但是后来大家由此引申出来的讨论引发了我的思考。

这些讨论的内容有点杂乱,边边角角都涉及一点。我花了些时间,写了一些testcase,试图找出其中的规律,并希望对大家有所帮助。

先来看一个简单的例子:
var test={
};

function test2() {
};

var test3 = function() {
}


这段代码可以说是最简单的javascript了,首先定义了一个名为test的object,一个名为test2的funciton,一个名为test3的function。

那么此时我们应该如何使用这三个变量呢?最简单的办法:直接引用。
而事实上,我们也可以用window这个包在他们外层的全局object名来引用他们, 即: window.test或者window.test2()。

那么,能不能用this来访问这些变量呢? 理论上讲,this现在应该就是指代window object才对。于是我试着这样访问this.test2().结果显示,成功。

第二个例子开始有点复杂:
var test={
    t1: 1,
    t2: this.t1,

    myTest: function() {
        var t1 = 11;
        return this.t1;
    }
};


在test中,只有一种定义语法是对的: variable: value,如果我想用var t1 = 1;这种方式的话,就会出现语法错误。

当我在test里面定义一个方法时,这个方法就从属于test object, 那么它内部的this就指向了test。所以myTest方法返回的值就应该是1,而不是11.如果我去掉this的话,则正好相反。

而当我尝试去获得t2的时候,却发现t2为undefine,也就是说t2是无法使用test中的其它变量来初始化的。

我试着把this改成test,结果却是test undefine。我把t2的初始化改成t2: test.myTest(),结果也是一样的,test undefine。
而我把之改成t2: this.myTest(),报出来的错又变成了this.myTest() undefine,哪怕我把该方法的定义放到了t2的前面。

由此可以得出的结论是,在定义一个对象时,该对象里面的对象是不能够获得this对象的,相应的,该对象里的object则没有问题。
因此,该对象可以改成这样:
var test={
    t1: 1,
    t2: 0,

    myTest: function() {
        var t1 = 11;
        test.t2 = test.t1;
        return this.t2;
    }
};

通过这种方法,test里的t2就可以通过调用被成功的初始化了。

看起来似乎很完美...

真的是这样吗?我们真的是没有办法获取this类型么? 我们刚刚对于报错的发现:使用this和使用test得到的错误是不一样的!也许此时的this,根本就不是test。

var g = 25;
var test={
    t1: 1,
    t2: this.g,
};

alert(test.t2);

得到的结果是25.

是不是觉得很吃惊? 此时的this居然指向的是test的外层,即window。另一方面,我们认为此时的test对象尚未创建完毕,因此无法访问。

我们必须为这种怪异的行为提供一个具有概念完整性的解释。

以下是我的理解,因此而造成的一切后果,本人概不负责...

在任何情况下,this都是指向该对象的容器的父亲(容器这个概念是我自己发明的,其本质也是一个对象),对于某个对象,如t1或者t2,他们的容器是test,所以this便指向test的父亲,即window,而window是已经预定义好的。 然而对于某个函数,如myTest,它本身就是容器,而它的父亲则是test,那么当你位于myTest容器内时,其中的this便指向这个容器的父亲test。这就解决了第一个问题:this的指向问题。

而javascript是解释性的语句,它是边读源码边解释的。当它遇到一个函数的定义时,暂时是不解释的,而是直接把source code保存下来。这就造成了定义变量的时候无法使用test,而调用函数(此时test已经定义好了)时则没有问题。

因此当js解释器遇到test时,整个过程是这样的:
var test={
    t1: 1,
    t2: this.t1,

    myTest: function() {
        var t1 = 11;
        return this.t1;
    }
};

1. 解释test,开始定义一个新对象。
2. 解释t1,放入该对象中。
3. 解释t2,尝试寻找test对象,因为test对象还在定义中,因此无法找到。
4. 解释myTest,是个方法,直接把代码拷贝到对象中。
5. 完成test对象的定义。

所以此时你再去调用myTest的时候,test对象已经定义完全,可以正确使用了。


接下来,我们看看function test2() {}这种定义形式:
function test2() {
    var t3 = 1;
    var t4 = t3;
    return t4;
};

我们之前魔咒一般的代码,在这里便轻松搞定,具体就不解释了,本身也是很简单的。

同样,根据前面的例子,可以猜出,此时的this指向的是window:

var g = 25;
function test2() {
    var t3 = 1;
    var t4 = t3;
    return this.g;
};


虽然我们知道,在js中,函数也是对象,但是像这种方法定义的函数,是无法获得其内部定义的局部变量的。不过有意思的是,我们还是可以写这样的代码:
function test2() {
    var t3 = 1;
    var t4 = t3;
    return test2.t22;
};

test2.t22 = 12;


此时,你可以把test2当作一个方法来使用test2();又或者当作一个对象来使用test2.t22,都是可以访问的。唯一要记住的就是,在test2中this指向的是window而不是test2.

那么如果我在这个方法里面定义对象或者方法,它的this是不是就是指test2这个function呢?

var g = 25;
function test2() {
    var t3 = 1;
    var t4 = {
    	t5: t3
    };
    
    var t6 = function() {
    	return t3;
    }
    return t4.t5;
};


结果显示,我们是可以访问的t3的,而t4和t6中的this,指向的居然也是window。
var g = 25;
function test2() {
    var t3 = 1;
    var t4 = {
    	t5: this.g
    };
    
    var t6 = function() {
    	return this.g;
    }
    return t4.t5;
};
alert(test2())

我们可以这样理解,当我们把test2当作函数来使用的时候,js解释器就一句一句执行该函数,而test2中的this显然是指向window的,所以test2里面的一切,也都指向window
了。而对于该环境中的任何变量,也都是可以直接访问到的了。

如果我们的猜想正确的话,如果我们把test2当作对象来使用,得到的应该就是另一种结果:
var g = 25;
function test2() {
    var t3 = 1;
};

test2.t4 = {t5: this.g};
test2.t6 = function() {
	return this.g;
};
alert(test2.t4.t5);
alert(test2.t6());

我们发现,t4.t5是可以访问的,而t6()的返回值则是undefine。这又是为什么呢?

其实也很简单,我们只要记住,变量是定义时环境,而函数则是执行是环境。这样我们就不会困惑了,因为对于t5而言,他就是定义是环境,那么this其实是指向当前大括号这个容器的父亲,也就是window。
而函数则要到运行时才会解释,而在运行时,它的this应该是指向test2.

说到这里,我只能说js实在是太绕了,写js也是一件非常痛苦的事情。

但是我们仍然需要继续下去,我们来看最后一个case:
var test3 = function() {
    var t7 = 1;
    return t7;
}
alert(test3());


基本而言这个函数和上一个仅仅是在形式上有一些区别,我并没有发现他们在使用上的差别。根据js几本比较重要的书籍上的介绍,都是推荐使用这种函数定义方法,因为这样可以“提醒用户函数也是对象”。


最后想提一点是,在函数中定义一个变量,一定要记得加var,否则就会出现下面这种情况:

var test3 = function() {
    var t7 = 1;
    t8 = 13;
    return t8;
}
alert(test3());
alert(t8);

t8已经变成了一个全局的变量。
分享到:
评论

相关推荐

    asp.net专家疑难解答200问源码

    21.如何在页面中应用javascript脚本-示例1 21.如何在页面中应用javascript脚本-示例2 22.如何实现从服务器端向页面动态添加javascript脚本-示例1 22.如何实现从服务器端向页面动态添加javascript脚本-示例2 24....

    西路疑难解答 v1.0

    1. **网页开发**:西路疑难解答v1.0作为一个在线应用,其前端界面的开发可能涉及到HTML、CSS和JavaScript。HTML用于构建页面结构,CSS用于美化页面样式,而JavaScript则用于实现交互效果,如表单验证、动态加载等。 ...

    ASP.NET专家疑难解答200问

    在《ASP.NET专家疑难解答200问》中,涵盖了多个关键知识点,这些知识点是ASP.NET开发过程中常见的问题和挑战。 1. **Web服务控件使用**:ASP.NET提供了多种内置控件,如Button、TextBox、GridView等,用于构建用户...

    asp.net专家疑难解答200问

    以上只是"ASP.NET专家疑难解答200问"中的一部分问题,实际涵盖的范围还包括ASP.NET Core、Entity Framework、SignalR、WCF、ASP.NET MVC的高级特性,以及与前端技术如HTML、CSS、JavaScript的交互等。学习和掌握这些...

    asp.net专家疑难解答200问.rar

    "ASP.NET专家疑难解答200问"这个压缩包文件很可能是针对ASP.NET开发中遇到的各种问题和挑战的集合,包含了200个具有代表性和常见性的问题及其解决方案。 首先,我们要理解ASP.NET的核心概念。ASP.NET不仅支持HTML、...

    Asp.Net专家疑难解答200问

    《Asp.Net专家疑难解答200问》的示例代码涵盖了Asp.Net开发中的诸多常见问题和解决方案,是开发者日常工作中不可或缺的参考资料。以下是一些关键知识点的详细解析: 1. **Asp.Net基础**:Asp.Net是微软推出的Web...

    erro-solucao-melhor-amigo-do-pablo:JAVASCRIPT ES6 +数组对象+ FILTER()+ MAP()+箭头功能+解构赋值(通过解构对数组进行归因)

    已发布的练习参考了BOOTCAMP的培训-NodeJS开发人员-JavaScript疑难解答( ) 挑战说明: 在今年年底,学校有一个聚会。 参加聚会的报名将于7月初开始。 注册后,学生可以选择是否要在聚会上成为“巴勃罗的朋友”。 ...

    erro-solucao-produto-e-divisao:JAVASCRIPT ES6 + MATCH()+ NUMBER()+ BIGINT()+ MAX_SAFE_INTEGER + TYPEOF

    已发布的练习参考了BOOTCAMP的培训-NodeJS开发人员-JavaScript疑难解答( ) 挑战说明: 您有义务测试计算器,以便它们仅执行乘法和除法运算。 此外,在每个操作中要输入的术语(显示屏上显示的数字将被相除或相乘...

    疑难解答前端

    标题 "疑难解答前端" 暗示我们即将探讨的是与前端开发相关的常见问题及解决方案,特别是涉及JavaScript这一重要编程语言的使用。在这个领域,开发者经常遇到各种挑战,如语法错误、浏览器兼容性问题、性能优化等。让...

    实习二动态网页制作基础与发布中疑难解答

    ### 实习二动态网页制作基础与发布中疑难解答 #### 关键知识点解析 在本次实习“动态网页地图制作”的过程中,遇到了一个与`<input type=image>`相关的疑问,特别是关于`image.x`和`image.y`这两个属性的应用,...

    PhotoShop常见的50个疑难问题及解答(20211118115316).pdf

    PhotoShop常见的50个疑难问题及解答(20211118115316).pdf

    调用JavaScript.zip

    这个压缩包中的内容可能包括具体的代码示例、步骤指南和可能的疑难解答,帮助开发者熟练掌握这一技能。在学习过程中,建议结合官方文档和其他相关教程进行深入研究,同时注意实践和测试,以确保理解和应用的正确性。

    javascript客户端验证和页面特效制作上机、课后练习答案(一)

    “在线指导2”可能是一个补充资料,提供了额外的实践项目或疑难解答,帮助学习者巩固所学知识并解决实际问题。 总结PPT则是一个全面回顾,它总结了所有章节的主要知识点,帮助学习者梳理学习路径,确保他们能够系统...

    疑难解答NG

    在IT领域,"疑难解答NG"可能是指针对各种复杂问题的高级解决策略,尤其是在网络、系统管理和编程中遇到的问题。这个标题暗示了我们将探讨一种针对技术难题的高级方法论,特别是与HTML相关的技术问题。 HTML...

    Cookie疑难解答-案例研究

    本文将针对"Cookie疑难解答-案例研究"这一主题,结合相关标签,如HTML、.NET、Windows、ASP.NET、IIS、Visual Studio、WebForms、ASP以及QA和Dev,深入探讨Cookie常见问题及其解决方案。 1. **Cookie不被发送到...

    javascript高级知识点,不适合初学者

    #### 十二、脚本疑难解答 在开发过程中,常见的脚本错误包括语法错误、逻辑错误等。 **解决方法**: - 使用浏览器开发者工具检查错误消息。 - 仔细检查代码,确保语法正确。 - 添加调试代码,如`console.log()`,...

    疑难解答:带有最终响应和打字稿的最终顶峰旅行应用程序的移动覆盖范围

    【标题】:“疑难解答:带有最终响应和打字稿的最终顶峰旅行应用程序的移动覆盖范围” 这篇描述可能指的是一个关于移动应用开发的项目,特别是针对“最终顶峰旅行应用程序”的问题解决过程。这个应用程序可能是一款...

Global site tag (gtag.js) - Google Analytics