# this

作者: 多叉树;转载须注明出处

# 一般概念

今天我们了解一些 this 关键字, 在JS 中, this代指当前对象的引用,至于代指哪个当前对象,还要看 this 所在的函数的上下文来判断, 所以this也被称为函数上下文

我们可以做个不太形象的类别, this 和 中文语境下的 “这” 很像, 如下面的这段话

小明学会了穿裤子, 这让小明爸爸很高兴

上面这段话, 这 单独拿出来先来没有任何意义, 放在这个句子中,我们就知道, ‘这’代指小明学会穿裤子这件事

中文中有很多这种联系 上下文的 词语 , 比如 这 , 那 , 那个, 上面 …

我们不是在讨论中文语法, 所以这里不展开来讲

我们说这么多, 就是让大家更加形象的立即 this 在 js中的作用。

下面再举个简单的例子,看看 this的基本用法


 <script>
    var xiaoming = {
        nickname: '小明',
        sayHello: function() {
            console.log('我是:',this.nickname);
        }
    }

    xiaoming.sayHello();
</script>

上面由于是 xiaoming 对象调用了 syaHello() 方法, 所以 this 代指的就是 xiaoming 这个对象

再举个例子

因此此时已经脱离了 xiaoming 对象,默认有 window对象调用, 而window对象并没有nickname、age属性


<script>
    var xiaoming = {
        nickname: '小明',
        sayHello: function() {
            console.log('我是',this.nickname);
        }
    }

    var sayHelloFun = xiaoming.sayHello;

    sayHelloFun();
</script>

上面这个例子会输出我是 undefined

因为我们把 一个函数赋值给了另外一个函数, 随后 其实 是Window对象调用了 sayHelloFun(); 所以这里的 this代指的就是 Window对象, 而window对象没有 name 属性,所以这里会输出一个 undefined

由此我们得出一个结论:

  1. 同一个函数, 用不同的对象去调用他,this 指代的 对象不同
  2. 函数只有在被调用的时候,其中包含的this才会明确知道上下文

也就是说, 再普通语法中,谁调用了相关函数, this 就指向谁

# 数组内的this引用

数组内的this引用

我们都知道, 数组的元素是可以包含函数类型的


<script>
	var array = ['A', 'B',  function () {
	    console.log(this[0]);
	}]
	
	array[2]();
</script>

这个例子会输出A, 函数内部的 this 指向的是 数组本身, 因为最终是数组在调用数组内的元素

# 立即执行函数的this引用

<script>

    var a = 1;
    var obj = {
        a: 2,
        fun: (function() {
            var a = this.a;
            console.log(a + this.a);
            return function() {
                console.log(a + this.a);
            }
        })()
    }

    obj.fun();
</script>

上面的例子会输出2 ,紧接着输出3; 执行步骤如下

  1. 立即执行函数 在被解析到的时候就会立即执行

    // 此时的this 指向 window, 立即执行函数的都是被 window 加载,所以指向他 a = 1
    var a = this.a;
    // 此时输出2
    console.log(a + this.a);
    
  2. 接着返回在一个函数,并将引用赋值 给 fun 句柄

     return function() {
    				// this : 谁调用我我指向谁 a = 1
            console.log(a + this.a);
      }
    
  3. 接着 obj 在调用 fun() 的时候,返回值 函数的 this 指向 obj, 所以 , this.a 在这一刻明确为 2

    // a = 1 , this.a = 2 , 最终结果: 3
    obj.fun();
    

# setTimeout 等异步执行函数的this引用

<script>
	var obj {
	    a: 1,
	    b: 2,
	    fun: function() {
	        console.log(this.a + this.b);
	    }
	}
	
	var a = 3;
	var b = 4;
	
	setTimeout(obj.fun, 200);

</script>

上面的这个例子会输出 7 ; 我们都知道 setTimeout 属于 window对象, 这里的 obj.fun (opens new window) 只是作为一个形参 传给了 setTimeout , 而真正执行调用的是Window对象

在看一个例子

<script>
    var obj = {
        a: 1,
        b: 2,
        fun: function() {
            console.log(this.a + this.b);
        }
    }

    var a = 3;
    var b = 4;

    setTimeout(obj.fun(), 2000);

</script>

这个例子, 实际是setTimeout的错误用法,

obj.fun() 在传参的时候因为加了‘()’就被执行了, 所以会打印出 3,我们实际上是把3传给了 setTimeout函数

此时的 setTimeout 没有发挥异步的作用

# call 和 apply

# 基本用法

我们前面讲了, 谁调用函数,this 就代指谁, 这个规律适用于类似于下面的这种调用语法

对象.函数()

而call、apply 可以改变 this的指向,他们的语法通常是这样

函数.call(对象, 函数所需参数1, 函数所需参数2, ....);
函数.apply(对象, 函数所需参数数组, 函数所需参数数组)

把哪个对象传入 call 和 apply函数中, this 就代表哪个对象

举例

<script>

	function sum() {
	  alert(this.chinese + this.math + this.english);
	}
	
	var xiaoming = {
	  chinese: 80,
	  math: 95,
	  english: 83
	}
	
	// 函数.call(上下文)
	// 函数.apply(上下文)
	sum.call(xiaoming);
	sum.apply(xiaoming);

</script>

# 两者区别


<script>
    
    function sum(b1, b2) {
        alert(this.chinese + this.math + this.english + b1 + b2);
    }

    var xiaoming = {
        chinese: 80,
        math: 95,
        english: 83
    }

		// call 要用逗号罗列参数
    sum.call(xiaoming, 1, 2);
		// apply 要把参数写到数组中
    sum.apply(xiaoming, [1, 2]);
    
</script>

使用call, 要把 原本函数所需的参数逐一罗列开; 使用 apply , 要把原有函数的参数封装到一个数组中