zoukankan      html  css  js  c++  java
  • js 中 this 的指向问题

    高程上的大前提:

    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 的指向,不过表现确实有点奇怪,看截图:

    image

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

     1 var name = "The Window";
     2 var object = {
     3     name: "My Object",
     4     getName: function() {
     5         return this.name;
     6     }
     7 };
     8 object.getName(); //"My Object"
     9 (object.getName)(); //"My Object"
    10 (object.getName = object.getName)(); //"The Window",在非严格模式下
    11 (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版

  • 相关阅读:
    01 mybatis框架整体概况(2018.7.10)-
    第一课(2018.7.10)
    JavaEE 企业级分布式高级架构师课程_汇总贴
    5-1条件运算符 & 5-2
    5-3运算符的优先级
    4-3逻辑非运算符及案例 & 4-4
    4-1逻辑与运算符介绍 & 4-2逻辑或运算符介绍
    3-3if-else条件结构 & 3-4 & 3-5
    3-2if条件结构
    3-1关系运算符
  • 原文地址:https://www.cnblogs.com/xianshenglu/p/8098793.html
Copyright © 2011-2022 走看看