JavaScript中this的问题

this

this是 JavaScript 语言的一个关键字。
它是函数运行时,在函数体内部自动生成的一个对象。
this总是指向调用它的对象

三个简单的应用场景

this一般用在函数,这里我根据函数的三个场景,通俗的分析下this的问题。

先不说this问题,我们先说说全局对象window。

你通过var定义的参数以及函数,实际上是全局对象window的一个属性。怎么说呢,看下下面的代码。

 	 var x = 1;
     function test() {
         console.log('I am function');
     }
     console.log(x); 		//1
     console.log(window.x); //1
     test(); 				//I am function
     window.test(); 		//I am function

通过上面的代码。就可以粗略理解成JavaScript中函数和var定义的参数实际是window的一个属性*。
(在这篇博客中,指javascript的普通环境,不涉及node.js的环境,因为node的全局对象不是window,而是Global)

在普通函数中调用

		var x = 1;
		function test(){
  		   console.log(this.x);
		}
		test();  //1

此时test,实际是通过window调用的,所以这里this指向window。

作为对象方法的调用

		test = function () {
   		     console.log(this.x);
 		};
  		var obj = {
 		     x:2,
		     test:test
		};
	    obj.test(); //2

此时test,通过obj调用,所以这里this指向obj,obj中x为2,所以打印2。

构造函数中调用

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

在构造函数中,this指向new出来的这个新对象。obj是test构建出来的,此时this指向obj。

稍微复杂点

	var x = 1;
    function test() {
        this.x = 2;
    }
    var obj = new test();
    alert("obj.x: " + obj.x);   //2
    obj.x = 3;
    test();
    x *= 10;
    alert("ojb.x: " + obj.x);   //3
    alert("x: " + x); 			//20

如果你能看懂上面的运行结果,那说明你this已经入门了。如果看不懂,那看看下面的代码。

	var x = 1;
    function test() {
        this.x = 2;
    }
    var obj = new test();
    alert("obj.x: " + obj.x); //2
    obj.x = 3;
    window.test();
    window.x *= 10;
    alert("ojb.x: " + obj.x); //3
    alert("x: " + window.x); //20

对比下,其实就是就是test和x在没被谁调用时,通过window调用他们,结果却是一样的,这就是平常容易出错的点。下面我详细说明下这段代码的过程。
1、var x 创建了一个全局的x,这个x算是window的一个属性。
2、test是一个函数(可以是普通函数,也可以是构造函数)。
3、通过test构造obj对象。
4、obj.x就是obj的属性x。
5、 obj.x = 3,修改了obj里面的x。
6、test(),在没用通过new的情况下,这里的test不是构造函数,而是window属性中的一个普通函数,实际通过window调用,此时this指向window,所以x是window的x。
7、x *= 10,这里的x就很明显是window的x了。
8、最终obj.x=3
9、最终window.x = 20

通过call,apply,bind改变this指向

这三都是用来改变this指向的,第一个参数是this指向的新对象,区别于第二个参数,以及返回值。
话不多说,直接代码解释

    var name = 'lin';
    var xw = {
        name : "小王",
        gender : "男",
        age : 20,
        bb:function(){
          console.log(this.name)
        },
        say : function(school,grade) {
            console.log(this.name + " , " + this.gender + " ,今年" + this.age + " ,在" + school + "上" + grade);
        }
    };
    var xh = {
        name : "小红",
        gender : "女",
        age : 21
    };
    xw.say('清华','大学');              //小王 , 男 ,今年20 ,在清华上大学
    xw.say.call(xh,'北大','大学');      //小红 , 女 ,今年21 ,在北大上大学
    xw.say.apply(xh,['北大','大学']);   //小红 , 女 ,今年21 ,在北大上大学
    xw.say.bind(xh,'北大','大学')();    //小红 , 女 ,今年21 ,在北大上大学
    xw.bb.call();                       //lin
    xw.bb.call(undefined);              //lin
    xw.bb.call(null);                   //lin

首先,有xw(小王)和xh(小红)两个对象。小红没有say这个方法。
xw自然可以调用自己的say方法,say方法中的this指向调用它的xw。
然后,我们可以利用call,apply,bind来改变say这个方法的this,让小红也能调用这个方法。
三个方法第一个参数都是xh,改变this指向,让this指向xh。
第二个参数,call和bind都是say方法中需要的参数,而apply是say方法中需要的参数组成的数组。
bind会返回改变this指向后的say方法,我们需要调用这个方法,不然没什么效果,所以得加()调用。
最后三行代码,当你不给这三个函数传参或者传了一个null或者undefined时,默认调用全局对象,将window传给这三函数,所以才会打印全局的name。

上一篇:Card Game Cheater HDU1528


下一篇:后台管理微服务(二)——docker的使用