详解javaScript中的this

javaScript中的this是变化的导致在很多地方this都不一样,于是很多小伙伴在开发的时候会很迷惑,详细理解清楚this将有助于我们在今后的学习中更好的理解其他的东西,下面就开始讲解this。

记住下面这几句话:

  • 函数预编译过程 this —> window  预编译的时候AO对象里面会有this键,它的值为window
  • 全局作用域里 this —> window
  • call/apply 可以改变函数运行时this指向
  • obj.func();   func()里面的this指向obj)

全局上下文

  • 无论是否在严格模式下,在全局执行上下文中(在任何函数体外部)this 都指代全局对象。

函数上下文

  • 先来看一句话:在函数内部,this的值取决于函数被调用的方式,但是箭头函数例外,下面会解释。

简单调用:

    不在严格模式下面 ,this 的值默认指向全局对象。

		不在严格模式下面 ,this 的值默认指向全局对象。
		例1:
			function f1(){
			  return this;
			}
			//在浏览器中:
			f1() === window;   // true 在浏览器中,全局对象是window
			
			//在Node中:
			f1() === global; // true

在严格模式下,this将保持他进入执行上下文时的值,所以下面的this将会默认为undefined。

	例2:	
		function f2(){
		  "use strict"; // 这里是严格模式 	
		  return this;
		}
		f2() === undefined; // true

之所以是这个样子,是因为在严格模式下,如果 this 没有被执行上下文(execution context)定义,那它将保持为 undefined

在这个例子当中this的确应该是undefined,因为f2是被直接调用的,而不是作为对象的属性或方法调用的(如 window.f2())。

我们还可以使用call()和apply()来调用函数,给他绑定this,具体的用法自己去查。需要注意的是,使用call和apply的时候,如果传递给 this 的值不是一个对象,JavaScript 会尝试使用内部 ToObject 操作将其转换为对象。

bind方法

  • ECMAScript 5 引入了 Function.prototype.bind。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,也就是返回了一个新的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。还需要注意的是,如果将this传递给call、bind、或者apply 它将被忽略。

 

箭头函数

    箭头函数也是es6出现的,解决了函数this不正确绑定的问题,和普通的函数不太一样,要区分开来理解。

    箭头函数的this与封闭词法上下文的this保持一致 ,即箭头函数内部的this指向被创建时的上下文 ,如果被创建时的上下文的this变化,那么箭头函数内部的this也会跟着变。

    下面我们通过例子来理解。

		例1:
			var foo = () => {
			 	return this
			 }
			 var obj = { 
			 	foo: foo
			 }
			 console.log(foo() === window) // true
			 console.log(obj.foo() === window) // true

例1中,foo这个箭头函数被创建时所在的上下文是window,当我们通过第一种方式调用时,它会返回的this就是window.当我们使用第二种obj.foo()方法来调用时候,foo不是一个箭头函数,而是一个普通的函数,那么按照前面说的那句话“在函数内部,this的值取决于函数被调用的方式”,来理解,此时,foo的this将会被绑定到obj,但是这里的foo是一个箭头函数,当它创建时,它的this就被绑定到window,所以即使是通过obj.foo()的方式来调用,它的this不会改变为指向obj,它仍然指向window。可以理解为箭头函数绑定到的this优先存在

		例2:
			var obj = {
			  bar: function() {
			    var x = () => { // 这里被创建时的上下文是bar这个function 那么这个function的this是什么,箭头函数的this就是什么
			    	return this 
			    } 	
			    return x;
			  }
			};
			var fn = obj.bar(); // 通过点调用时bar的this被绑定到obj 箭头函数的this就是obj
			console.log(fn() === obj); // true
			var fn2 = obj.bar; //获得了引用但是没调用this不会被绑定到obj
			console.log(fn2()() == window); //true

在例2中,我们在内部声明的箭头函数被创建时的上下文是bar这个函数上下文,那么这个函数的this是什么,箭头函数的this就是什么。接着我们使用了两种方式来调用这个bar函数。第一种是通过obj.bar()调用,此时bar的this被绑定到obj,那么此时箭头函数的this也指向obj。第二种方式是先使用fn2 = obj.bar获得了引用,但是没调用,所以此时bar的this不会被绑定到obj,然后
使用f2()()调用bar,此时相当于可以这样理解  window.f2()(),那么此时bar的调用者是window,所以它的this将会指向window,因此此时箭头函数内部的this现在也是window。

		例3:
			var obj = {
				foo: () => {
					return this
				}
			};
			var fo = obj.foo
			console.log(fo() === obj) // true

在例3中,虽然是先获取的引用,没有先把foo的this绑定为obj,但是foo被创建时的上下文就是obj,因此不管是通过obj.foo()直接调用,还是先获取引用再调用,得到的结果都是一样的。这里的fo()任然可以理解为window.fo(),理论上也是foo的this会被绑定到全局,但是内部使用的箭头函数,也可以像例1一样理解为箭头函数绑定到的this优先存在。

原型链中的this:

如果该方法存在于一个对象的原型链上,那么this指向的是调用这个方法的对象

		例子:
			function test () {

			}
			test.prototype.sayName = function () {
				return this
			}
			var person = new test()
			console.log(person.sayName() === person) //true

作为构造函数:

它的this被绑定到正在构造的新对象。这句话的意思是当你执行 var person = new Person()时候 this指向正在被构造的新对象person

作为一个DOM事件处理函数:

当函数被用作事件处理函数时,它的this指向触发事件的元素 

作为一个内联事件处理函数(写在标签内用""包含):

它的this指向当前的DOM元素

其他

函数调用函数,被调用的函数的this指向window,这里说的普通函数,箭头函数会受所创建时的上下文的this影响

		例1:使用普通函数
			var obj = {
	  		foo: test1,
	  		}
			function test1 () {
				function test2 () {
					return this
				}
				return test2()
			}
			console.log(obj.foo() === window) // true

这里虽然test1的this被绑定为obj 但是当test1调用特殊test2时,这个this仍是window

		例2:使用箭头函数
			var obj = {
	  			foo: test1,
	  		}
			function test1 () {
				var test2 = () => this
				return test2()
			}
			console.log(obj.foo() === obj) // true

由于箭头函数内部的的this是所创建时的上下文也就是test1,所以这里是true

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值