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

Javascript中的this——理解Javascript中的作用域【转载】

阅读更多
大家在使用Javascript的时候经常被this这个家伙搞得晕头转向的。对大多数有OOP开发经验的开发人员来说this是当前作用域中引用普通元素的标识符,但是在Javascript中它却显得古灵精怪的,因为它不是固定不变的,而是随着它的执行环境的改变而改变。在Javascript中this总是指向调用它所在方法的对象。

举一个简单的例子:
view plaincopy to clipboardprint?
function test(){  
alert(this);  
}  
var obj=function(){  
var name='testObj';  
}  
obj.objTest=test;  
test();  
obj.objTest();  


把这段代码放到HTML中运行这个页面,你会看到首先提示一个警告[object window],然后第二个警告

view plaincopy to clipboardprint?
var obj=function(){  
var name='testObj';  
}  


我们先定义了一个test()方法,并在方法内部调用alert()方法将this显示出来,然后定义了一个obj函数对象,并给它加了一个私有的字段name,同时给它加了一个静态的方法objTest(),而这个函数则直接指向test()函数。

分别调用test()和obj.objTest()方法,第一次警告框提示的是Window对象,而第二次提示的是我们定义的obj这个函数的代码。这说明了test函数在两次执行的时候this的值是不同的!

这就说明了当调用函数的对象不同的时候,其内部的this关键字指代的对象是不同的。这里需要值得注意的是Javascript是基于对象的语言,当我们的变量或者函数定义在<script></script>标签的根下的时候其实相当于给window对象加了相应的属性或方法,所以当我们利用function test(){}代码定义一个函数的时候,其实相当于给window对象添加了一个新的函数,即window.test()函数。
我们可以做一个实验:
view plaincopy to clipboardprint?
function test(){  
    alert(this);  
}  
alert(test===window.test);  

警告框提示的将是true,这说明当我们在调用test()这个函数时相当于调用的是window.test()。所以当我们调用test()函数的时候调用这个函数的对象其实是window对象,this指代的是window对象,所以我们在alert(this)的时候弹出的警告窗口内容是[object Window]。我们将obj.objTest=test相当于把obj.objTest()指向test(),所以当我们调用obj.objTest()函数时相当于在obj调用了test()这个函数,所以现在this指代的是obj对象,提示的就是obj这个Function也就是我们看到的代码。

说到这应该也解释的差不多了,可能上面的例子太抽象,想象不出来它能在什么情况下用到,那我们现在就假设一个需求,做一个贴近实用一点的例子。
假设我们现在页面中的所有超链接在点击之后颜色要改为红色,用Javascript实现。大体的思路应该是获取页面中所有的<a>标签,然后遍历所有的<a>标签,给每一个注册一个click事件,事件触发后我们将它的color值设为red。
示例代码如下:
view plaincopy to clipboardprint?
//改变颜色  
function changeColor(){  
    this.style.color='#f00';  
}  
//初始化,给所有 a 标签注册事件  
function init(){  
    var customLinks=document.getElementsByTagName('a');  
    for(i in customLinks){  
        //你也可以使用事件侦听器方式来注册事件  
        //由于要兼容IE,FF等浏览器可能需要更多代码,您可以自行编写  
        customLinks[i].onclick=changeColor;  
    }  
}  
window.onload=init;  


将这段代码添加到HTML文档中,并在文档中添加一些超链接,当超链接点击后颜色会变成红色,这里我们定义的changeColor()函数中this关键字在点击超链接触发函数的时候它指代的是当前这个超链接。而如果你直接调用changeColor()函数浏览器会报错,提示Error: ‘this.style’ is null or not an object或者undefined之类的错误。

不知道说到这能不能让正在看文章的你对Javascript中的this关键字有了一些自己的了解呢?或者你已经不耐烦了?(:P)

其实要想真正对这个问题有更深入的理解那么必须对Javascript的作用域和作用域链有深入的理解。

作用域,顾名思义就是指某一属性或方法具有访问权限的代码空间,简单的说也就是这个变量或方法它在代码中的的适用范围。在大多数的OOP中主要有public,private,protect三种作用域,对着三种作用域在这里就不详细解释了,如果有OOP的经验应该都有深入的了解。在这里我要说的是这三种作用域类型对Javascript来说几乎是毫无意义的,因为Javascript中只有一种公共作用域,在Javascript中作用域是在函数中进行维护的。举个例子:
view plaincopy to clipboardprint?
var test1='globle variable';  
function example(){  
    var test2='example variable';  
    alert(test1);  
    alert(test2);  
}  
example();  
alert(test1);  
alert(test2);  

根据我们前面解释的,这里的test1变量相当于window的一个属性,所以它会在整个window作用域内起作用,而test2则在example()函数的内部声明,所以它的作用域也就维持在example()方法的内部,如果在函数的外部调用test2浏览器会提示出错。而在example()内部调用test1则没问题。
根据这个我们再举一个例子:
view plaincopy to clipboardprint?
var test='globle variable';  
function example(){  
    var test='example variable';  
}  
example();  
alert(test);  

这个例子运行会是什么结果呢?对,警告框会提示“globle variable”,因为example()函数内部的test变量其作用域只维持在内部,不会影响外部的test变量。如果我们将example()内部test变量的var关键字去掉呢?你可以自己试试。

说到这就有牵扯出另外一个概念,那就是作用域链的概念。作用域链就是可以确定变量值的路径。由上面一个例子可以看出,var关键字是用来维护作用域链的,如果变量使用了var关键字声明那么他就可以看作为作用域链的终点。同样函数的形参的定义也会起到类似的作用。

说到这你对this这个精灵古怪的家伙有了比较清晰的认识了吧?根据它简单的一个诠释,this总是指向调用它所在函数的对象,根据作用域和作用域链,我们会很清晰的确定this的真面目。临末尾再来一个开始那个例子的简单变化
view plaincopy to clipboardprint?
function test(){  
    alert(this);  
}  
var obj=function(){  
    var name='testObj';  
}  
obj.objTest=test;  
obj.objTest2=function(){  
    test();  
}  
test();  
obj.objTest();  
obj.objTest2();  

你猜会提示什么内容呢?你可以运行一下试试(:P);

既然this是根据调用其所在函数的对象的改变而改变的,那我们可不可以强制改变它的调用对象呢?答案是肯定的,以后的文章会介绍一下这部分内容,以及Javascript中不同类型的数据成员的实现方式,闭包等概念。

转载:http://www.dklogs.net/?p=253

分享到:
评论

相关推荐

    深入理解JavaScript系列

    深入理解JavaScript系列(14):作用域链(Scope Chain) 深入理解JavaScript系列(15):函数(Functions) 深入理解JavaScript系列(16):闭包(Closures) 深入理解JavaScript系列(17):面向对象编程之一般...

    深入理解javascript作用域第二篇之词法作用域和动态作用域

    本文是深入理解javascript作用域系列第二篇——词法作用域和动态作用域 词法作用域  第一篇介绍过,编译器的第一个工作阶段叫作分词,就是把由字符组成的字符串分解成词法单元。这个概念是理解词法作用域的基础  ...

    深入理解javascript原型和闭包1

    JavaScript通过作用域链解决自由变量的查找问题,作用域链连接了当前作用域与上层作用域,允许在不同作用域中访问变量。 (15)——闭包 闭包是JavaScript中一种强大的特性,它允许函数访问并操作其词法作用域内的...

    JavaScript动态网页开发详解——源文件

    - **函数**:函数定义、函数表达式、参数传递、作用域、闭包。 2. **进阶篇**: - **对象与属性**:对象字面量、构造函数、原型链、this指向、Object的方法(如assign、getOwnPropertyDescriptor等)。 - **数组...

    Javascript學習筆記——JS的函數

    本篇文章将深入探讨JavaScript中的函数,包括它们的定义、参数、返回值、作用域以及一些高级特性。 1. 函数定义: 在JavaScript中,函数可以使用`function`关键字来定义。例如: ```javascript function sayHello...

    关于javascript 回调函数中变量作用域的讨论

    在JavaScript中主要有两种作用域类型——全局作用域和局部作用域。 - 全局作用域: 在函数外部声明的变量可以在整个程序中访问。 - 局部作用域: 在函数内部声明的变量只能在该函数内部访问。 3. **闭包**: 是一种...

    JavaScript 语言精粹

    此外,《JavaScript语言精粹》还会深入讨论作用域、变量提升、this关键字、事件处理、DOM操作以及异步编程,如回调函数、Promise和async/await。这些知识点对于前端开发人员来说至关重要,因为它们直接影响到网页的...

    javascript视频教程

    7. **闭包**:闭包是JavaScript中的一个重要特性,允许函数访问并操作其外部作用域的变量,即使在其外部作用域已被销毁后依然有效。 8. **模块化**:JavaScript提供了多种模块化方案,如CommonJS(Node.js中使用)...

    深化浅析JavaScript中的Function类型_.docx

    在全局作用域中,`this`通常指向全局对象(在浏览器中是`window`),在对象方法中,`this`指向调用该方法的对象。在函数调用中,`this`的确定较为复杂,需要根据调用方式(常规调用、apply/call方法、箭头函数等)来...

    Javascript权威指南(第六版中+英文版)+源代码.zip

    这包括理解变量、数据类型(如字符串、数字、布尔值、对象、数组等)、运算符(算术、比较、逻辑、赋值等)、控制结构(条件语句如if...else,循环如for、while)以及函数——JavaScript的核心组成部分。书中详细...

    JavaScript对象模型-执行模型

    对于`let`和`const`声明,JavaScript引入了块级作用域,它们不会被提升。 此外,JavaScript是单线程的,但通过事件循环(Event Loop)和异步编程模型(如回调函数、Promise、async/await)来处理并发任务。事件循环...

    JavaScript语言精粹(JavaScript.The.Good.Parts).pdf

    7. **性能优化**: 提供了有关如何优化JavaScript性能的建议,包括减少DOM操作、避免全局作用域污染等技巧。 8. **文档与资源**: 为读者提供了丰富的参考资料,包括在线文档、社区资源等,帮助读者进一步学习和研究。...

    javascript电子教程2

    同时,会深入讨论函数作用域,包括全局作用域、局部作用域以及闭包,这是JavaScript中高级特性的基础。 **第8部分:对象与数组** 这部分介绍了JavaScript的核心数据结构——对象和数组。对象是键值对的集合,可以...

    Java Script 经典教程(七)——JavaScript用户指南

    - **作用域**:了解全局作用域和局部作用域,以及ES6的块级作用域。 3. **对象与数组** - **对象**:JavaScript中的对象是键值对的集合,通过花括号`{}`创建。属性访问可以用点号或方括号语法。 - **数组**:...

    【JavaScript源代码】详解JavaScript中的链式调用.docx

    2. **返回对象本身**:这种方法与`this`的作用域链类似,但直接返回对象实例,而不是`this`。这在非构造函数或不涉及原型链的情况下也很有用。 ```javascript var person = { age: null, setAge: function(age){...

    so和such用法小结.doc

    首先在自身作用域中查找,如果没有找到,则向上搜索直到全局作用域。闭包的作用域链包含了其自身作用域和包含它的外部作用域。 8. 使用let和const防止变量提升 使用`let`和`const`声明的变量不会被提升到作用域...

    JAVASCRIPT-使用面向对象的技术创建高级 Web 应用程序

    闭包是JavaScript中一个强大的特性,允许函数访问其外部作用域中的变量,即使这些变量在函数执行后仍然存在。这对于实现数据封装和模拟私有属性非常有用。 **模拟私有属性** 虽然JavaScript中没有原生的私有属性...

    Java Script 经典教程(三)——java script 专业设计

    箭头函数的语法简洁,其this指向与父级作用域保持一致,解决了回调函数中this指向的问题。此外,我们还需要理解闭包的概念,它是JavaScript实现数据封装和模块化的一种方式。 在JavaScript中,对象是核心概念。通过...

    JavaScript 2.0 The Complete Reference, Second Edition

    4. **函数与闭包**:讲解函数作为一等公民的概念,函数表达式、作用域、闭包以及函数的this指向。 5. **面向对象编程**:讨论JavaScript的面向对象特性,如类的模拟、继承、多态等。 6. **正则表达式**:详细解释...

    javascript手册

    同时,它会介绍作用域、闭包和this关键字,这些都是JavaScript中深入理解的对象和概念。 JavaScript手册.doc全面覆盖了JavaScript语言的基础语法和高级特性。从变量声明(var、let、const)、控制流(条件语句、...

Global site tag (gtag.js) - Google Analytics