• js this指向练习题


    this指向及应用

    关于js中的this指向问题:有很多同学刚接触js时,对this的指向问题很是迷惑,在有些不常见情况,往往搞不清到底指向谁。对此,我们只需记住一点:this始终指向调用它的对象。废话少说,下面直接通过不同情况下的实例来说明其指向问题。
    1、对象中的方法中的this,指向调用它的对象,即 b ,所以 this.a 的输出结果是b对象中的a的值; 如果b对象中没有a,则this.a的输出结果是 undefined。

    var o = {
        a: 10,
        b: {
            a: 12,
            fn: function(){
                console.log(this.a); // 输出结果是 12
                console.log(this); // 输出结果是 b 对象
            }
        }
    }
    //调用
    o.b.fn(); 
    var o = {
        a: 10,
        b:  {
            fn: function(){
                console.log(this.a); // undefined
                console.log(this);   // b对象
            }
        }
    }
    //调用
    o.b.fn(); 

    2、改变调用方法,不直接调用:改用赋值后调用,此时this的指向为window,所以this.a的输出结果为 undefined,因为全局中没有全局变量a。

    var o = {
        a: 10,
        b: {
            a: 12,
            fn: function(){
                console.log(this.a); //undefined 若在对象o外定义a,则输出的就是其在外定义的值(全局变量)
                console.log(this);   // window
            }
        }
    }
    var j = o.b.fn; //只是将b对象下的方法赋值给j,并没有调用
    j(); //调用,此时绑定的对象是window,并非b对象直接调用

    3、在对象方法中调用时:

    var point = { 
        x : 0, 
        y : 0, 
        moveTo : function(x, y) { 
            this.x = this.x + x; 
            this.y = this.y + y;
            console.log(this.x); // 1
            console.log(this.y); // 1
        } 
    }; 
    point.moveTo(1, 1)//this 绑定到当前对象,即 point 对象

    4、作为函数调用时

    function someFun(x) { 
        this.x = x; 
    } 
    someFun(5); //函数被调用时,this绑定的是全局对象 window,相当于直接声明了一个全局变量x,并赋值为5
    console.log(x); // x 已经成为一个值为 5 的全局隐式变量

    更复杂一点的情况:如下所示,point对象中的x、y没有被改变,并结果中多了两个新的全局变量x,y,值都为1。根本原因是point对象下的moveTo方法中的moveX与moveX方法在调用时都是全局调用,绑定的对象都是window。

    var point = { 
        x : 0, 
        y : 0, 
        moveTo : function(x, y) { 
           // 内部函数
           var moveX = function(x) { 
               this.x = x;
           }; 
           // 内部函数
           var moveY = function(y) { 
               this.y = y;
           };
           moveX(x); // 这里是全局调用
           moveY(y); 
        }; 
    }; 
    point.moveTo(1, 1); 
    console.log(point.x); // 0
    console.log(point.y); // 0

    可以通过下面情况输出结果说明:

    var point = { 
             x : 0, 
             y : 0, 
             moveTo : function(x, y) { 
                 this.x = x;
                 console.log(this.x); // 1
                 console.log(this);   // point对象
    
                 // 内部函数
                 var moveX = function(x) { 
                    this.x = x;
                 }; 
                 // 内部函数
                 var moveY = function(y) { 
                    this.y = y;
                 } 
                 moveX(x); // 这里是全局调用
                 moveY(y); 
             } 
        }; 
        point.moveTo(1, 1); 
        console.log(point.x); // 1
        console.log(point.y); // 0
        console.log(x); // 1
        console.log(y);// 1

    像如上对象中函数方法所示,本意是改变point对象中的x、y的值,而非新建全局变量。所以可以通过以下方法避免上述情况:

    var point = { 
             x : 0, 
             y : 0, 
             moveTo : function(x, y) { 
    
                 var that = this; //内部变量替换
    
                 // 内部函数
                 var moveX = function(x) { 
                     that.x = x; 
                    // this.x = x;
                 }; 
                 // 内部函数
                 var moveY = function(y) { 
                     that.y = y;
                    // this.y = y;
                 } 
                 moveX(x); //这里依然是全局调用,但是在给变量赋值时,不再是this指向,而是that指向,而that指向的对象是 point。
                 moveY(y); 
             } 
        }; 
        point.moveTo(1, 1); 
        console.log(point.x); // 1
        console.log(point.y); // 1
        console.log(x) // 报错 x is not defined
        console.log(y) //

    另附将moveX、moveY由内部函数改为非内部函数后的一种情况示例:这种情况下moveX、moveY方法的调用时绑定在moveTo对象上的,因为moveTo对象一开始是没有x、y变量的,所以执行 this.x = x、this.y = y之后,相当于在moveTo对象中新建了两个变量。

    var point = { 
             x : 0, 
             y : 0, 
             moveTo : { 
                 // 内部函数
                 moveX: function(x) {
                    console.log(this) // {moveX: ƒ, moveY: ƒ}
                    this.x = x;
                 },
                 // 内部函数
                 moveY: function(y) { 
                    this.y = y;
                 }
             } 
        }; 
        point.moveTo.moveX(1); 
        point.moveTo.moveY(1);
        console.log(point.moveTo);  // {moveX: ƒ, moveY: ƒ, x: 1, y: 1}
        console.log(point.x); // 0
        console.log(point.y); // 0
        console.log(x) // x is not defined
        console.log(y) //

    5、作为构造函数调用:

    function Point(x, y){ 
           console.log(this); // point对象
           this.x = x; 
           this.y = y; 
           this.moveTo = function(x,y){
              this.x = x;
              this.y = y;
              console.log(this.x);//1 10
              console.log(this.y);//1 10
           }
        }
        var p1 =  new Point(0,0); //注意这种形式方法的调用及apply、call的使用
    
        var p2 = {
            x:0,
            y:0
        }
        p1.moveTo(1,1); 
        p1.moveTo.apply(p2,[10,10]);
    
        console.log(x);// x is not defined
        console.log(y);// 

    6、this在不同场景中的指向
          ①匿名函数中的this指向全局对象

    var a = 10;
    var foo = {
        a: 20,
        fn: (function(){
            console.log(this); // window
            console.log(this.a); // 10
        })()
    }

          ②setInterval和setTimeout定时器中的this指向全局对象

    var a = 10;
    var oTimer1 = setInterval(function(){
        var a = 20;
        console.log(this.a); // 10
        clearInterval(oTimer1);
    },100);

          ③eval中的this指向调用上下文中的this

    (function(){
        eval("console.log(this)"); // Window
    })();
    function Foo(){
        this.bar = function(){
            eval("console.log(this)"); // Foo
        }
    }
    var foo = new Foo();
    foo.bar();

          ④apply和call中的this指向参数中的对象

    var a = 10;
    var foo = {
        a: 20,
        fn: function(){
            console.log(this.a);
        }
    };
    var bar ={
        a: 30
    }
    foo.fn.apply();//10(若参数为空,默认指向全局对象)
    foo.fn.apply(foo);//20
    foo.fn.apply(bar);//30

    附:eval、apply、call方法的说明:
    eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
    call 、apply 这个两个函数的第一个参数都是 this 的指向对象,第二个参数的区别如下:
      call的参数是直接放进去的,第二第三第n个参数全都用逗号分隔,直接放到后面 obj.myFun.call(db,'params1', ... ,'paramsn' );
      apply的所有参数都必须放在一个数组里面传进去 obj.myFun.apply(db,['params1', ..., 'paramsn' ]);
    以上。

  • 相关阅读:
    JDBC statement的常用方法
    JDBC通过资源文件初始化
    django 常用命令
    pip 设置国内源
    Python中注释与声明
    PyQt5程序基本结构分析
    机器学习中常见的专业术语
    给Linux安装中文的man手册
    Vim:Vim入门级配置
    Linux 目录结构与目录操作
  • 原文地址:https://www.cnblogs.com/zjx304/p/10671243.html
Copyright © 2020-2023  润新知