• 【原】理解javascript中的this


      最近的文章基本都是总结javascript基础内容的,因为我觉得这些东西很重要。而且很多时候你觉得你理解了,其实并没有你自认为的那么理解。十月份没怎么写文章,因为国庆出去玩的比较久,心变野了,现在是时候重新回到学习的轨迹了,今天要总结的是javascript中的this.

    介绍this之前,先来两句话,这两句话比较重要,可以说贯穿全文。

    1、this的最终指向的是那个调用它的对象

    2、如果一个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象

    下面通过一些代码示例来讲解this

    1、window中的this

    demo1

    function test1(){
        this.x = 1;
        console.log(this.x);
      }
    test1();  // 1
    
    function test2(){
        var y = 2;
        console.log(this.y); //undefined
        console.log(this);  //Window
    }
    test2();

     上面的两个例子中,都是属于属于全局性调用,因此this就代表全局对象。也就是为什么test2打印出来的this.y会是undefined,因为this指向了 window.

    2、在对象中使用this 

    demo2

    var x=0;
    var obj={
        x:1,
        fn:function(){
            console.log(this.x);
        }
    }
    obj.fn();  // 1

    这里的this指向对象obj,因为调用的fn是通过obj.fn()执行的。

    不过这里有个注意点,就是this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,这个是比较重要的一点。为了验证这句话,稍微改造一下上面的demo2

    demo3

    var x=0;
    var obj={
        x:1,
        fn:function(){
            console.log(this.x);
        }
    }
    obj.fn();  // 1  跟上面的代码一样
    
    // 修改了这里
    var obj2=obj.fn;
    obj2();  //0

    demo3中和demo2的不同之处在于,没有直接调用obj里面的fn函数,而是将其赋值给obj2,最终通过obj2来调用fn函数。

    而obj2属于全局变量,因为fn里面的this指向了 window。这个也验证了上面那句话: this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁

    demo4

    var obj = {
        x:1,
        y:{
            fn:function(){
                console.log(this.x); //undefined
            }
        }
    }
    obj.y.fn();

    如果一个对象中又包含有其他对象,this仅仅会指向它的上一级对象。
    就像demo4中,fn里面调用this.x,这个this只会指向fn的上一级对象y。y中没有x这个变量,所以返回的是undefined。

    稍微改造一下demo4,再次来验证一下:this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁

    demo5

    var obj = {
        x:1,
        y:{
            x:2,
            fn:function(){
                console.log(this.x); //undefined
            }
        }
    }
    var obj2=obj.y.fn;
    obj2();  // 因为此时fn中的this指向了window

    3、在构造函数中使用this

    demo6

    function Fn(){
        this.x=1;
    }
    var myFn=new Fn();
    console.log(myFn.x); //1

    如果函数倾向于和 new 关键词一块使用,则我们称这个函数是构造函数, 在函数内部,this 指向新创建的对象。也就是说,这个this不是指向函数Fn,而是指向它的实例 myFn。

    4、call和apply,改变this指向(这里顺便把call和apply给介绍了

    在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,也就是说,是为了改变函数体内部 this 的指向。

    call和apply的区别就在于传递方式的不同,call在接收指定参数的形式是 someMethod.call(obj, arg1, arg2);

    而apply在接收指定参数时的形式是 someMethod.apply(obj, [arg1, arg2]).或者someMethod.apply(obj, arg1),但是这个arg1必须是一个类数组对象

    demo7

    var personA = {
        name: 'kobe',
        sayName: function (hobby){
            console.log(this.name + ' likes ' + hobby);
        } 
    };
    
    personA.sayName('basketball');   // 'kobe likes basketball'
    
    var personB = {
    
        name: 'James'
    }
    
    personA.sayName.call(personB, 'basketball');  // 'James likes basketball'
    personA.sayName.apply(personB, ['basketball']); // 'James likes basketball'
    
    

    personA.sayName('basketball'); 这段代码中,调用sayName()这个方法的对象是personA,因此sayName()内部的this指向就是personA对象。
    personA.sayName.call(personB, 'basketball'); 本来sayName方法的this指向是personA对象,但是调用call/apply后,this对象指向了personB对象。

    
    

    也可以这么理解,personA.sayName.call(personB, 'basketball')其实就是 personB.sayName(‘basketball’);



    demo8
    function PersonA(name,hobby) {
       this.name = name,
       this.hobby = hobby,
       this.say = function() {
            console.log(name +" likes " + this.hobby + '.');
       }
    }
    function PersonB(name,hobby) {
       PersonA.call(this,name,hobby);
    }
    
    var Fn=new PersonB('James','basketball');
    Fn.say(); // James likes basketball.

    虽然我们没有在PersonB对象里添加任何属性和方法,但是我们使用call()继承了原本属于PersonA 的属性和方法。就可以做到 PersonA 函数所有能做到的事情。

    这里额外再穿插一下appy的使用一些场景

    apply应用场景1:数组合并

    var list1 = [0,1,2];
    var list2 = [3,4,5];
    [].push.apply(list1,list2);
    
    //或者 Array.prototype.push.apply(list1, list2); 
    
    console.log(list1);//  [0,1,2,3,4,5]

    apply应用场景2:获取数组中的最大值或者最小值

    var arr = [0,1,2,15,6];
    var getMax=Math.max.apply(this,arr);
    console.log(getMax); //15

    5、使用this的注意点

    这里主要介绍 setTimeout或者setInterval中使用this的注意点

    demo9

    var name='james';
    var person={
      name:'koBe',
      sayName:function(){
         setTimeout(function(){
            console.log(this.name);
         },0);
      }
    }
    person.sayName();  // james

    因为setTimeout()这个异步函数调用的时候,内部的回调函数this的指向是window.刚好window中有一个 name为 james的标量。所以输出james.

    那如何将setTimeout中的this指向 person呢。两种方式:

    方法一:将this保存在一个变量中

    demo10

    var name='james';
    var person={
      name:'koBe',
      sayName:function(){
        var that=this; //将this存储在that中。
         setTimeout(function(){
            console.log(that.name);
         },0);
      }
    }
    person.sayName();  // koBe

    将this保存在that中,这样,setTimeout调用this.name就变成了that.name了。

    方法二:使用bind

    demo11 

    var name='james';
    var person={
      name:'koBe',
      sayName:function(){
         setTimeout(function(){
            console.log(this.name);
         }.bind(this),0);
      }
    }
    person.sayName();  // koBe

    bind方法,起的作用和call,apply一样,都是改变函数/方法执行时,this的指向,确保这个函数/方法运行时this指向保持一致。

    demo11中,通过bind方法将this对象绑定为person。那么回调函数在执行的时候,this指向还是person。

    有误之处,欢迎指出

  • 相关阅读:
    影院售票系统
    返璞归真
    【C++】【STL】【map】基础知识干货
    书签-技术类
    正则表达式-正则表达式校验金额最多保留两位小数
    winCommand-cmd杀死进程
    idea快捷键-总结
    接口封装-泛型方法、泛型接口、lambda表达式【类似ios传递block】
    treeMap-get返回null,因为比较器出问题
    git-linux一个月更新80万行代码,如何保证项目稳健?
  • 原文地址:https://www.cnblogs.com/xianyulaodi/p/5956431.html
Copyright © 2020-2023  润新知