本文主要讨论一下JS的作用域和this关键字。作用域,就是你的方法或者变量可访问的区域,是他们执行的上下文。如果你见过这样的代码:

function someFunc() {
var _this = this;
something.on("click", function() {
console.log(_this);
});
};

你就会很好奇为什么要用this赋值给一个变量_this呢?你看完这篇文章就会清楚这个问题的答案了。

第一种作用域叫做全局作用域(Global Scope)这很容易定义,如果一个方法、变量是全局作用域的,那么它就可以从任何的地方访问到。在浏览器里,全局作用域就是window对象。所以,如果你的代码里有:

var x = 9;

你其实是在给window.x赋值为9(在浏览器里运行的时候)。如果你喜欢的话,也可以写成window.x = 9,当然这不是很必要。全局作用域对象的属性可以在代码的任何地方访问到。

另外的作用域就只有局部作用域了。在JavaScript里一般就是一个方法内部的作用域。比如:

function someFunction() {
var x = 5;
}
console.log(x); // undefined

变量x是在方法内部初始化的,那么就只能在方法内部访问。

一些需要注意的地方

如果你声明了一个变量,而且在声明的时候忘记使用var关键字。那么,这个变量自动被置为全局变量。比如:

function someFunction(){
x = 5;
} // 执行一个这个方法,完成x的全局设置
someFunction(); console.log(x); // 5

这是一个非常差的实践。你应该尽量少的往全局作用域添加属性。这也是为什么你会经常看到一些库,比如jQuery会这么干:

(function() {
var jQuery = {/*全部的方法都在这里*/};
window.jQuery = jQuery;
})();

把全有的属性、方法都放在一个方法里。然后立刻执行这个方法就会把全部的属性和方法都绑定在了局部作用域里。最后把jQuery对象绑定到全局作用域,间接的把之前定义的属性和方法都暴露出来方便调用。显然我大量的减少了jQuery的代码,但是这就是jQuery代码如何工作的。

由于局部作用域只有通过方法的定义来实现。任何在一个方法内部定义的方法都可以访问外部方法里定义的变量。比如:

function outer() {
var x = 5;
function inner() {
console.log(x); // 5
} inner();
}

但是outer()方法不可以访问inner()方法定义的任何变量。

function outer() {
var x = 5;
function inner() {
console.log(x); // 5
var y = 100;
} inner();
console.log(y); // undefined
}

这很容易理解。但是当我们试图要探究this关键字的时候就又变得复杂了。我相信很多人都遇到过这样的问题:

${'myLink'}.on('click', function() {
console.log(this); // 指向myLink $.ajax({
// 设置ajax相关
success: function() {
console.log(this); // 指向的是全局对象。 ???
}
});
});

this是在方法执行的时候自动赋值的变量。它的值和方法的调用方式有很大的关系。比如:

function foo() {
console.log(this); // global object
} theApp = {};
theApp.foo = function() {
console.log(this); // 指向theApp对象
} var link = doeument.getElementById('myLink');
link.addEventListener('click', function() {
console.log(this); // 指向link
});

MDN对第三个例子的解释非常到位:

事件的this总是指向出发这个事件的元素对象。比如使用一个通用的事件监听器来处理一系列的有相似事件的元素。当使用addEventListener把一个方法添加到一个元素的事件处理器的时候,这个方法的this值就被改变了。注意,this的值是从调用者里传给方法的。

这么做:$('myLink').on('click', function() {})意味着link被点击的时候方法就会执行。由于这个方法是处理link的事件的,所以this的值就是这个link元素。

在Ajax请求的success回调方法只是一个普通的方法。所以,当它被调用的时候this指向的是全局对象。任何对象,不是对象方法或者事件的时候会遇到的情况。

上面的原因也就是你在很多地方看到var _this = this;或者var that = this;的原因。来看一个例子:

$('myLink').on('click', function() {
console.log(this); //指向myLink
var _this = this;
$.ajax({
// ajax设置
success: function() {
console.log(this); // 指向全局对象
console.log(_this); // 指向myLink
}
});
});

原文地址:https://javascriptplayground.com/javascript-variable-scope-this/

JavaScript的this和作用域的更多相关文章

  1. javascript中的变量作用域以及变量提升

    在javascript中, 理解变量的作用域以及变量提升是非常有必要的.这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解. 变量作用域 “一个变量的作用域表示这个变量存在的上 ...

  2. javascript中的变量作用域以及变量提升详细介绍

    在javascript中, 理解变量的作用域以及变量提升是非常有必要的.这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解变量作用域 “一个变量的作用域表示这个变量存在的上下文 ...

  3. Javascript的块级作用域

      一.块级作用域的说明 在学习JavaScript的变量作用域之前,我们应当明确几点: a.JavaScript的变量作用域是基于其特有的作用域链的. b.JavaScript没有块级作用域. c. ...

  4. Javascript中闭包的作用域链

    作用域定义了在当前上下文中能够被访问到的成员,在Javascript中分为全局作用域和函数作用域,通过函数嵌套可以实现嵌套作用域. 闭包一般发生在嵌套作用域中.闭包是JavaScript最强大的特性之 ...

  5. 从头开始学JavaScript (二)——变量及其作用域

    原文:从头开始学JavaScript (二)--变量及其作用域 一.变量 ECMAscript变量是松散型变量,所谓松散型变量,就是变量名称可以保存任何类型的数据,每个变量仅仅是一个用于保存值的占位符 ...

  6. javascript模仿块级作用域(第一篇)

    作用域有词法作用域和块级作用域之分,javascript属于词法作用域,而在java.C++中却是块级作用域.在javascript中,只有函数能够创建作用域,作用域是以function作为边界的. ...

  7. javaScript函数提升及作用域

    代码片段: var a = 1; function foo() { console.log(a); //输出为undefined if (!a) { var a = 2; } alert(a); }; ...

  8. 《前端之路》之四 JavaScript 的闭包、作用域、作用域链

    04:JavaScript 的闭包 一.定义: 常规定义: 闭包的定义: 有权利访问外部函数作用域的函数. 通俗定义: 1.函数内部包含了函数.然后内部函数可以访问外部函数的作用域. 2.内部函数可以 ...

  9. JavaScript 执行环境、作用域、内存管理及垃圾回收机制

    前言 JavaScript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存. [原理]找出那些不再继续使用的变量,然后释放其占用的内存.为此,垃圾收集器会按照固定的时间间隔( ...

  10. Javascript我学之四作用域

    本文是金旭亮老师网易云课堂的课程笔记,记录下来,以供备忘 作用域 JavaScript的变量作用域只有两种,全局作用域和函数作用域. 函数的作用域 函数中定义的变量是私有的,仅在本函数范围内有效,称为 ...

随机推荐

  1. Linux指令--mv

    本文博客转自:http://www.cnblogs.com/peida/archive/2012/10/27/2743022.html mv命令是move的缩写,可以用来移动文件或者将文件改名(mov ...

  2. Netty初探

    匠心零度 转载请注明原创出处,谢谢! 说在前面 为什么我们需要学习netty?谈谈自己的看法,由于本人水平有限,如果有那里不对,希望各位大佬积极指出,欢迎在留言区进行评论交流.探讨. 由于移动互联网的 ...

  3. php中HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR的使用

    1.REMOTE_ADDR:浏览当前页面的用户计算机的ip地址2.HTTP_X_FORWARDED_FOR: 浏览当前页面的用户计算机的网关3.HTTP_CLIENT_IP:客户端的ip 在PHP 中 ...

  4. nginx配置中root与alias的区别

    nginx指定文件路径有两种方式root和alias,这两者的用法区别,使用方法总结了下,方便大家在应用过程中,快速响应.root与alias主要区别在于nginx如何解释location后面的uri ...

  5. CGI编程

    1简介 .CGI:通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口,服务器和客户端之间的通信,是客户端的浏览器和服务器端的http服务器之间 ...

  6. 面向切面编程之cglib代理方式

    思想: 和上一篇面向切面编程之手动JDK代理方式上的需求和开发模式一样.不同的是目标类没有接口,只有实现类,采用的是spring中提供的Enhancer类继承目标类实现的代理方式. 需要导入的jar包 ...

  7. ABP官方文档翻译 3.7 领域事件(事件总线)

    领域事件(事件总线) 事件总线 注入IEventBus 获取默认实例 定义事件 预定义事件 处理异常 实体更改 触发事件 处理事件 处理基础事件 处理者异常 处理多个事件 注册处理者 自动 手动 取消 ...

  8. MIB Browser如何导入已编译的mib

    开发过程中,如果需要来回在几套mib之间来回切换,每次都进行编译工作那将是一件很繁琐的事情,我们可以直接导入已经编译好的mib文件,避免重复的编译工作. 第一步,备份已经编译好的mib文件.    将 ...

  9. HDU 4825 Xor sum

    trie树的异或和问题 本题是一道经典题,使用trie树维护所给出的集合,我们知道等比数列前n项的和比第n+1项小,所以本题可以使用贪心策略,对于每一个询问,我们从高位向低位匹配,寻找最大异或值,向下 ...

  10. HDU 3949 XOR [高斯消元XOR 线性基]

    3949冰上走 题意: 给你 N个数,从中取出若干个进行异或运算 , 求最后所有可以得到的异或结果中的第k小值 N个数高斯消元求出线性基后,设秩为$r$,那么总共可以组成$2^r$中数字(本题不能不选 ...