• 深入探究js中无所不在的this


     黄金守则:

           this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window而当函数被作为某个对象的方法调用时, this等于那个对象。

    下面是一些相关实践:

    ------------------------------------------------->闭包相关的this<--------------------------------------------------------

    我们知道,匿名函数的执行环境具有全局性,因此this对象通常指向window,但是由于闭包的编写方式不同,这一点可能不那么明显:

     

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

    不过下面这样改写,就可以做到了。

     ----------------------------------------------->函数相关的this<-----------------------------------------------------

    先看一个最最简单的例子:

    this当然会undefined,因为this的指向实际是指向它的调用的。实际上,前面这样说是不对的,谢小胡子的提醒呢。实际上这个undefined是整个函数的运行结果,函数并没有返回任何值,所以它才是undefined的~~~

    下面还有两个特殊的情况,闭包中this的表现:

    因为闭包立即执行,这相当于在全局的作用于下调用了函数,于是乎,可以看到,他就是指向了window了。

    可是.......strict模式下的:

    这就是闭包中使用严格模式的后遗症,它不让this指向全局作用域了呢。

    这有个总结javascript中‘use strict’的资料,总结的挺好听明白的:http://www.web-tinker.com/article/20125.html

    那么说了this是指向他的调用了,到底是怎么指向的呢,我们试试几个小例子,看看它的行为:

    1.最普通的:

    看吧,刚才还undefined呢,调用一下this就指向调用它的作用域了喔。

    这个更印证了this指向调用他的作用域。

    2.那我现在把函数嵌套一下试试看呢:

    还是window喔,这里this是属于window喔,好像说也说不清楚,自己写写试试想想,体会体会喔。

    3.上面基本上都是函数调用时候的情况,那下面我试一下函数引用,来看看会是什么样子呢,稍稍复杂些:

    上面事实证明,引用函数是可以改变函数的执行作用域的,但是像之前的,调用函数是不会改变函数的执行作用域的呢:

    事实证明条用函数是不会改变函数的执行作用域的(注意上面两段代码中me:后面的使用方式)。

    这有道题目:

    ------------------------------------------------>构造函数中的this<----------------------------------------------------

    1.下面我们先看看js中简单封装过程中用到的this:

    上面实现的并不是严格的封装,但是从中我们可以看到this的作用。

    2.别急,肯定还是有点有意思的事情的:

    这里通过new创建了一个新的对象呢,并将这个对象通过this传入到了构造器中,这也就是为什么b的作用域跑到了a{}里面。

    这是为什么呢?? 我们来来看new构造函数这种用法是怎么回事吧:

    简单来看:

    其实new的作用就是使this指向一个新建的对象,然后return this。

    实际它的运行情况是这样的:

    复制代码
    1 function Person (){
    2     // var obj = new Object();
    3     // this = obj;
    4     alert(this);     // new 出来的 Person 对象
    5     // return this;
    6 }
    7 var person = new Person(); 
    复制代码

    实际上js的实现是这样的:

    复制代码
    1 function newOperator(Constr, args) {
    2     var thisValue = Object.create(Constr.prototype); // (1)
    3     var result = Constr.apply(thisValue, args);
    4     if (typeof result === 'object' && result !== null) {
    5         return result; // (2)
    6     }
    7     return thisValue;
    8 }
    复制代码

    在网上看资料的时候看到的,链接在这里:http://speakingjs.com/es5/ch17.html#_the_new_operator_implemented_in_javascript

    --------------------------------------------->call和apply对this的影响 <------------------------------------------------------------

    看例子:

    这里this就指向String了。

    上面这个例子就通过call(),把x,y,传到了函数中。

    ------------------------------------------------------->定时器(setTimeout,setInterval)中的this<--------------------------------------------------------------

    先看最简单的:

    这里面this就是指向window。

    实际上因为setTimeout()和setInterval()发放根本就是window的,所以当然指向window了。

    更加印证了上面所说的。

    但其实是,setTimeout()就是会产生一个不符合常理的this。它会在一个独立的执行上下文中运行。结果就是,他就会使this关键字指向window。 mdn上有详细的解释:https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers.setTimeout

     1 myArray = ["zero", "one", "two"];
     2 myArray.myMethod = function (sProperty) {
     3     alert(arguments.length > 0 ? this[sProperty] : this);
     4 };
     5 
     6 myArray.myMethod(); // prints "zero,one,two"
     7 myArray.myMethod(1); // prints "one"
     8 setTimeout(myArray.myMethod, 1000); // prints "[object Window]" after 1 second
     9 setTimeout(myArray.myMethod, 1500, "1"); // prints "undefined" after 1.5 seconds
    10 // let's try to pass the 'this' object
    11 setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object"
    12 setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error

    但是mdn上面 也提供了解决方法:

    1 myArray = ["zero", "one", "two"];
    2 myArray.myMethod = function (sProperty) {
    3     alert(arguments.length > 0 ? this[sProperty] : this);
    4 };
    5 
    6 setTimeout(alert, 1500, "Hello world!"); // the standard use of setTimeout and setInterval is preserved, but...
    7 setTimeout.call(myArray, myArray.myMethod, 2000); // prints "zero,one,two" after 2 seconds
    8 setTimeout.call(myArray, myArray.myMethod, 2500, 2); // prints "two" after 2.5 seconds

    --------------------------------------------------------------->eval()中的this<---------------------------------------------------------------------------

    直接调用eval():

    直接调用eval()的话,this指向当前作用域的。('use strict'不用也是一样的)

    下面展示了不直接调用的情况:

    ------------------------------------------------------->复杂情况中的this<--------------------------------------------------------

    在查找资料的过程中,发现了一个总结的挺好的,复杂情况下this的优先级,贴过来收藏:

    优先级 情景 this 的值 备注
    1 new new出来的空 object  
      apply / call 传入的参数 并列第一,apply / call不能和 new 同时出现
    new arr1.show.apply(“1”); // 报错
    2 定时器 window  
    3 事件 发生事件的元素  
    4 方法 所有者  
    5 其他(嵌套等) window || undefined 看是否为严格模式

    注:不管如何修改this,this只会影响一层

    例:

  • 相关阅读:
    「luogu2350」[HAOI2012] 外星人
    「csp校内训练 20191030」解题报告
    「csp校内训练 20191025」解题报告
    「2019纪中集训Day23」解题报告
    「luogu3974」[TJOI2015] 组合数问题
    「csp校内训练 20191106」解题报告
    「csp校内训练 20191024」解题报告
    「NOI2019d2t1」弹跳
    「2019纪中集训Day21」解题报告
    「csp校内训练 20191104」解题报告
  • 原文地址:https://www.cnblogs.com/skylar/p/4042663.html
Copyright © 2020-2023  润新知