高程上的大前提:

1、this 对象是在运行时基于函数的执行环境绑定的:在全局函数中,this 等于window,而当函数被作为某个对象的方法调用时,this 等于那个对象;不过,匿名函数的执行环境具有全局性,因此其this 对象通常指向window。

2、每个函数在被调用时都会自动取得两个特殊变量:this 和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量;

总结:

1、在事件处理程序中,事件绑定在哪个元素身上,this 就指向谁;分析戳这里;

2、在方法调用(如果某个对象的属性是函数,这个属性就叫方法,调用这个属性,就叫方法调用)中,执行函数体的时候,作为属性访问主体的对象和数组便是其调用方法内 this 的指向。(通俗的说,调用谁的方法 this 就指向谁;)

3、普通函数执行里的 this 都是 全局对象,非严格模式下浏览器端指的是 window(严格模式下 undefined,因为全局变量对象里没有定义this),因为都是在全局环境下执行的;

4、任意函数里如果嵌套了 函数,那这个时候 嵌套函数里的 this 在未指定的情况下,应该指向的是 window 对象(浏览器中非严格模式下,严格模式下返回 undefined ,因为嵌套函数里活动对象未指定 this);如果想在嵌套函数中继续用原来的 this 指向,需要保存下,比如 var self = this ,然后在嵌套函数中使用 self 变量,因为 this 不会传递;

这里加个案例:

var arr = [1, 2, 3];
arr.map(function() {
console.log(this);
});

你觉得这里 this 是 arr 对象么?

不是的,全局环境下,输出三个 window,你可能以为上面的理论错了,其实不是,map 作为 arr 对象的方法,在 map 函数里访问 this 当然是 arr 对象,而这里相当于在 arr.map 函数里又嵌套了一层函数,没指定的情况下,this 当然是 window,这里容易混淆,注意理解;

这里重写了默认的 map 方法,方便理解:

var arr = [1, 2, 3];

arr.map = function(fn) {
console.log(this); //输出 arr 对象
fn();
}; arr.map(function() {
console.log(this);//输出 window ,全局环境下
});

如果要把 map 里的 this 保存到嵌套的函数里:

var arr = [1, 2, 3];

arr.map = function(fn) {
fn.call(this); // 法一:把 this 作为参数传进去,替换了原来 fn 中的 this
var self=this; // 法二:保存下来,在嵌套函数里用
(function () {
console.log(self);
}()); }; arr.map(function() {
console.log(this);
});

这样就输出两次 arr 对象了,call 不会用点这里

5、通过构造函数创建对象,在调用构造函数之前就已经创建了新对象,并将构造函数的作用域赋给了新对象,因此构造函数里的 this 指向的就是这个新对象;

6、with 语句并没有改变 this 的指向,不过表现确实有点奇怪,看截图:

7、一些特殊情况,如:逗号运算符,赋值运算符

 var name = "The Window";
var object = {
name: "My Object",
getName: function() {
return this.name;
}
};
object.getName(); //"My Object"
(object.getName)(); //"My Object"
(object.getName = object.getName)(); //"The Window",在非严格模式下
(object.getName, object.getName)(); //"The Window",在非严格模式下

第9行代码解释:

虽然加上括号之后,就好像只是在引用一个函数,但this 的值得到了维持,因为object.getName 和(object.getName)的定义是相同的。

根据 MDN ,圆括号运算符() 用来控制表达式中的运算优先级。所以书上说,没有改变 this,我觉得是说的过去的;

第10行代码解释:

代码先执行了一条赋值语句,然后再调用赋值后的结果。因为这个赋值表达式的值是函数本身,所以this 的值不能得到维持,结果就返回了"The Window"。

我的理解是,赋值表达式返回了内存中的一个值,也就是函数本身,而不是原来方法的引用,所以 this 没有得到维持,结果返回了 window;

第11行代码解释:

同上,因为根据 MDN ,逗号操作符 也是返回最后一个操作数的值,也是函数本身,所以和上面一样;

按照这个逻辑的话,所有返回值操作的,都有可能去改变上面代码中的 this 值,都需要谨慎,譬如:

var a = {
func: function() {
return this;
}
}; function f(fn) {
console.log(fn());
} f(a.func);//window

因为函数中的参数也是按照值传递的,在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量。

参考资料:

JavaScript权威指南-第6版

JavaScript高级程序设计-第3版

js 中 this 的指向问题的更多相关文章

  1. 理解js中this的指向

         学习自原文  http://www.cnblogs.com/pssp/p/5216085.html后的一点小结(原文作者总结的很棒^_^)! 关于js中this的指向,在函数定义的时候还无法 ...

  2. js中this的指向

    在js中this的指向对于新手来说一定是个难题,但是如果你真正理解了的话,也就没什么问题啦,下面就来讲讲this吧. JS中,this的值取决于调用的模式(调用对象),而JS中共有4种调用模式: 1. ...

  3. JS中的this 指向问题

    我发现在对JS的学习中有很多朋友对this的指向问题还是有很大的误区或者说只是大致了解,但是一旦遇到复杂的情况就会因为this指向问题而引发各种bug. 对于之前学习过c或者是Java的朋友来说可能这 ...

  4. 轻松了解JS中this的指向

    JS中的this指向一直是个让人头疼的问题,想当初我学的是天昏地暗,查了好多资料,看的头都大了,跟他大战了那么多回合,终于把它搞定个七八分,其实往往都是我们复杂化了,现在就让大家轻松看懂this的指向 ...

  5. js中改变this指向的call、apply、bind 方法使用

    前言: 由于js 中this的指向受函数运行环境的影响,指向经常改变,使得开发变得困难和模糊,所以在封装sdk,写一些复杂函数的时候经常会用到this 指向绑定,以避免出现不必要的问题,call.ap ...

  6. js中 this 的指向

    js中 this的指向一共存在3种地方: 1.全局的this; 2.构造函数的this; 3.call/apply; 一.全局的this: function test(){ this.d = 3;// ...

  7. 彻底理解js中this的指向,不必硬背。

    首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...

  8. 了解学习JS中this的指向

    [转] 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问 ...

  9. JS中this的指向问题

    JS中this的定义:this对象是在运行时基于函数的执行环境绑定的(通俗点来说就是:this代表当前函数属于哪个对象). this一般情况下都代表的是global对象,在浏览器中就是window对象 ...

  10. Js中的this指向问题

    函数中的this指向和当前函数在哪定义的或者在哪执行的都没有任何的关系分析this指向的规律如下: [非严格模式]1.自执行函数中的this永远是window [案例1] var obj={ fn:( ...

随机推荐

  1. PHP is_callable 方法

    is_callable (PHP 4 >= 4.0.6, PHP 5) is_callable — 验证变量的内容是否能够进行函数调用 Description bool is_callable  ...

  2. 基于Redis构建10万+终端级的高性能部标JT808协议的Gps网关服务器(转)

    原文地址:http://www.jt808.com/?p=1282 在开发一个大规模的部标GPS监控平台的时候,就算我们花费再多的时间设计和规划,我们也并不能准确的预测出自己未来的车载终端接入量有多大 ...

  3. BS Web窗体 动态修改WebConfig文件参数及数据库链接串

    WebConfig操作帮助类 /// /// ConfigurationOperator 的摘要说明 /// public class ConfigurationOperator : IDisposa ...

  4. maven使用deploy发布到本地仓库

    使用maven可以方便的开发好的jar包发布到本地仓库中,方便其他项目依赖使用,在pom.xml文件中添加如下的配置: <distributionManagement> <repos ...

  5. vue知识点2018.6.3

    文件夹和文件名称 简介 build 构建脚本目录 config 应用程序的配置文件 index.html 入口页面 node_modules 存放 NPM 依赖模块 package-lock.json ...

  6. 使用Crypto++库的CBC模式实现加密(二)

    前面已经有一篇介绍使用Crypto++库实现的加密的文章了,但是代码中考虑的不完全,所以就重新发了个二 C++封装: #include "zyaes.h" #include < ...

  7. 替换元素节点replaceChild()

    替换元素节点replaceChild() replaceChild 实现子节点(对象)的替换.返回被替换对象的引用. 语法: node.replaceChild (newnode,oldnew ) 参 ...

  8. hive优化总结

    一.表设计 合理分表 合理设计表分区,静态分区.动态分区 二.扫描相关 1.谓词下推(Predicate Push Down) 2.列裁剪(Column Pruning) 在读数据的时候,只关心感兴趣 ...

  9. Bootstrap学习笔记(3)--菜鸟网CDN

    Bootstrap CDN 推荐 本站实例采用的是自建的静态资源库上的Bootstrap资源. <!-- 新 Bootstrap 核心 CSS 文件 --> <link href=& ...

  10. -/bin/sh: /usr/bin/xxx: not found”

    运行/usr/bin/helloworld命 令是提示“-/bin/sh: /usr/bin/helloworld: not found”,一开始我以为是helloworld没有运行权限,不过我给了它 ...