JavaScript的this

xiaoxiao2021-02-28  137

this关键字一直在JavaScript中是一个神秘的东西,对非常有经验的JavaScript开发者,有时也很难说this到底指向什么。本文是整理一些的this指向问题以及自己的看法,希望有帮助。

this到底是个什么东西?一直让人琢磨不透?

很多人会有以下两种对于this的误会:

1.this在一个函数中指向自身。

2.this指向函数的作用域。

        其实,this是在运行时进行绑定的,并不是在编写时绑定的,它的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。当一个函数调用时,会创建一个活动记录(有时候成为执行上下文)。这个记录会包含在哪里被调用(调用栈),函数的调用方式,传入的参数信息。this就是这个记录的一个属性,会在函数执行过程中用到。

1.默认绑定

最常见的函数调用类型:独立函数调用 function foo(){ console.log(this.a); } var a = 2; foo(); //2调用foo()时,this.a被解析成了全局变量a,因为函数调用时应用了this的默认绑定,指向全局对象。 如果在严格模式下,则不能将全局对象用于默认绑定,因此this会绑定到undefined。 function foo(){ 'use strict' console.log(this.a); } var a = 2; foo(); //TypeError:this is undefined

2.隐式绑定

通过 . 引用的函数,this会指向所引用的对象上去。 function foo(){ console.log(this.a); } var obj = { a:2, foo:foo } obj.foo(); //2当obj.foo引用foo函数,这里面地this就指向了Obj了。当函数引用有了上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。 隐式丢失 一个常见的this绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定,从而把this绑定到全局对象或undefined上,取决于是否是严格格式。 function foo(){ console.log(this.a); } var obj = { a:2, foo:foo } var bar = obj.foo; //函数别名 var a = "global"; bar(); // global虽然bar是obj.foo的一个引用,但实际上,它的引用是foo函数本身,因此此时的bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定。 还有一种出乎意料的情况发生在传入回调函数时: function foo(){ console.log(this.a); } function doFoo(fn){ //fn其实引用的是foo fn(); } var obj = { a:2, foo:foo } var a = "global"; doFoo(obj.foo); //global参数传递其实就是一种隐式绑定,因此我们传入函数时也会被隐式赋值,所以结果和上一个例子一样。 还有一种情况也和上面的一样,调用回调函数的函数可能会修改this。

3.显式绑定

在分析隐式绑定时,必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this间接绑定到这个对象上。如果不想在对象内部包含函数引用,而是在某个对象上强制调用函数,怎么做? JavaScript提供的绝大多数函数以及自己创建的所有函数都可以使用Call(。。。)和apply(。。。)方法。 他们的第一个参数是一个对象,是给this准备的,接着在调用函数时将其绑定到this。这种方式叫做显式绑定。 function foo(){ console.log(this.a); } var obj = { a:2, } foo.call(obj); //2显示绑定仍然无法解决之前丢失绑定问题。 硬绑定 function foo(){ console.log(this.a); } var obj = { a:2, } var bar = function(){ foo.call(obj); } bar(); //2 setTimeout(bar,100); //2 //硬绑定的bar()不可能再修改它的this bar.call(window); //2我们创建了函数bar(),并在它的内部手动调用了foo.call(obj),因此强制把foo的this绑定到了obj。无论之后如何调用函数bar,它总会手动在obj上调用foo。这种绑定是一种强制绑定,因此成为硬绑定。

4.new绑定

对一个构造函数进行调用new实例,this就指向这个实例对象。 使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作: 1.创建或者说构造一个全新的对象 2.这个新对象会被执行原型连接 3.这个新对象会绑定到函数调用的this 4.如果函数没有返回其他的对象,那么new表达式中的函数调用会自动返回这个新对象。 function foo(a){ this.a = a; } var bar = new foo(2); console.log(bar.a); //2

5.箭头函数

ES6中介绍了一种无法使用上面的规则的一种特殊函数,叫做箭头函数。箭头函数是根据外层(函数或者全局)作用域来决定this。 function foo(){ //返回一个箭头函数 return (a)=>{ //this继承自foo() console.log(this.a); } } var obj1 = { a:2 } var obj2 = { a:3 } var bar = foo.call(obj1); bar.call(obj2); //2,不是3!foo()内部创建的箭头函数会捕获调用时foo()的this。由于foo()的this绑定到obj1,bar(引用箭头函数)的this也会绑定到obj1,箭头函数的绑定无法被修改,new也不行! 判断this顺序 1.由new调用?绑定到新创建的对象。 2.由call或者apply(或者bind)调用?绑定到指定的对象。 3.由上下文对象调用?绑定到那个上下文对象。 4.默认:在严格模式下绑定到undefined,否则绑定到全局对象。
转载请注明原文地址: https://www.6miu.com/read-30549.html

最新回复(0)