this指向
const obj={ a:10, c:this.a, getA:function(){ return this.a } } console.log(obj.c); //undefined(this指向window) console.log(obj.getA()); //10(this指向obj) const test = obj.getA; console.log(test()); //undefined(this指向winoow)
// 当执行体为函数时,才是谁调用谁是this
let a = 10 const b = 20 function foo () { console.log(this.a) console.log(this.b) } foo(); console.log(window.a)
undefined;undefined;undefined;
let 或者 const
,变量是不会被绑定到window
上的
var a = 1 function foo () { var a = 2 function inner () { console.log(this.a) } inner() } foo()
在inner
中,this
指向的还是window(我的理解:inner()执行,与跟所处的this环境无关,只与谁执行了);答案为1
function foo () { console.log(this.a) // 1 } var obj = { a: 1, foo } var a = 2 obj.foo()
this 永远指向最后调用它的那个对象
隐式丢失其实就是被隐式绑定的函数在特定的情况下会丢失绑定对象。
有两种情况容易发生隐式丢失问题:
1.使用另一个变量来给函数取别名
function foo () { console.log(this.a) }; var obj = { a: 1, foo }; var a = 2; var foo2 = obj.foo; obj.foo();//1 foo2();//2
2.将函数作为参数传递时会被隐式赋值,回调函数丢失this绑定
function foo () { console.log(this.a)//2 } function doFoo (fn) { console.log(this)// obj2{...} fn() } var obj = { a: 1, foo } var a = 2 var obj2 = { a: 3, doFoo } obj2.doFoo(obj.foo)
现在调用obj2.doFoo()
函数,里面的this
指向的应该是obj2
,因为是obj2
调用的它。
但是obj.foo()
打印出来的a
依然是2
,也就是window
下的。
如果你把一个函数当成参数传递到另一个函数的时候,也会发生隐式丢失的问题,且与包裹着它的函数的this指向无关。
在非严格模式下,会把该函数的this绑定到window上,严格模式下绑定到undefined。
显式绑定
通过call()、apply()
或者bind()
方法直接指定this
的绑定对象, 如foo.call(obj)
。
这里有几个知识点需要注意:
1.使用.call()
或者.apply()
的函数是会直接执行的
2.bind()
是创建一个新的函数,需要手动调用才会执行
3..call()
和.apply()
用法基本类似,不过call
接收若干个参数,而apply
接收的是一个数组
function foo () { console.log(this.a) } var a = 2 foo.call()//2 foo.call(null)//2 foo.call(undefined)//2
如果call、apply、bind
接收到的第一个参数是空或者null、undefined
的话,则会忽略这个参数。
var obj1 = { a: 1 } var obj2 = { a: 2, foo1: function () { console.log(this.a) }, foo2: function () { setTimeout(function () { console.log(this) console.log(this.a) }, 0) } } var a = 3 obj2.foo1() obj2.foo2()
结果:2;Window{...};3
对于obj2.foo1()
,我们很清楚,它就是打印出2
。
但是对于obj2.foo2
呢?在这个函数里,设置了一个定时器,并要求我们打印出this
和this.a
。
想想我前面说过的话,谁调用的函数,函数内的this
指向的就是谁。
而对于setTimeout
中的函数,这里存在隐式绑定的隐式丢失,也就是当我们将函数作为参数传递时会被隐式赋值,回调函数丢失this
绑定,因此这时候setTimeout
中的函数内的this
是指向window
的。
var obj1 = { a: 1 } var obj2 = { a: 2, foo1: function () { console.log(this.a) }, foo2: function () { setTimeout(function () { console.log(this) console.log(this.a) }.call(obj1), 0) } } var a = 3 obj2.foo1() obj2.foo2()
结果:2;{ a: 1 };1
var obj1 = { a: 1 } var obj2 = { a: 2, foo1: function () { console.log(this.a) }, foo2: function () { function inner () { console.log(this) console.log(this.a) } inner() } } var a = 3 obj2.foo1() obj2.foo2()
结果:2 ;Window{...} ;3
function foo () { console.log(this.a) } var obj = { a: 1 } var a = 2 foo()//2 foo.call(obj)//1 foo().call(obj)// 报错
foo.call()
和foo().call()
的区别了,一个是针对于函数,一个是针对于函数的返回值。
function foo () { console.log(this.a) return function () { console.log(this.a) } } var obj = { a: 1 } var a = 2 foo()//2 foo.call(obj)//1 foo().call(obj)//2,1
foo()()//2,2
第一个数字2
自然是foo()
输出的,虽然foo()
函数也返回了一个匿名函数,但是并没有调用它呀,只有写成foo()()
,这样才算是调用匿名函数。
第二个数字1
是foo.call(obj)
输出的,由于.call()
是紧跟着foo
的,所以改变的是foo()
内this
的指向,并且.call()
是会使函数立即执行的,因此打印出1
,同理,它也没有调用返回的函数。
第三个数字2
是foo().call(obj)
先执行foo()
时打印出来的,此时foo()
内this
还是指向window
。
在执行完foo()
之后,会返回一个匿名函数,并且后面使用了.call(obj)
来改变这个匿名函数的this
指向并调用了它,所以输出了1
。
第四个,foo()
函数内的this
虽然指定了是为obj
,但是调用最后调用匿名函数的却是window
var name = 'window' function Person (name) { this.name = name this.foo = function () { console.log(this.name) return function () { console.log(this.name) } } } var person1 = new Person('person1') var person2 = new Person('person2') person1.foo.call(person2)()//person2,window person1.foo().call(person2)// person1,person2
person1.foo.call(person2)()
将foo()
函数内的this
指向了person2
,所以打印出person2
,而内部返回的匿名函数是由window
调用的,所以打印出window
。person1.foo().call(person2)
是将匿名函数的this
显式绑定到了person2
上,所以打印出来的会是person2
。var name = 'window' var obj1 = { name: 'obj1', foo1: function () { console.log(this.name) return () => { console.log(this.name) } }, foo2: () => { console.log(this.name) return function () { console.log(this.name) } } } var obj2 = { name: 'obj2' } obj1.foo1.call(obj2)()//obj2,obj2 obj1.foo1().call(obj2)//obj1 obj1 obj1.foo2.call(obj2)()//window window obj1.foo2().call(obj2)//window obj2
它里面的this
是由外层作用域来决定的,且指向函数定义时的this
而非执行时
字面量创建的对象,作用域是window
,如果里面有箭头函数属性的话,this
指向的是window
构造函数创建的对象,作用域是可以理解为是这个构造函数,且这个构造函数的this
是指向新建的对象的,因此this
指向这个对象。箭头函数的this
是无法通过bind、call、apply
来直接修改,但是可以通过改变作用域中this
的指向来间接修改。
调用函数里面的函数()(),正常情况是window,可以通过bind,call,apply改变;
或者函数里面的函数,是箭头函数,其this是其离他最近一层作用域的this;
若是new实例化的函数,这个函数有一层作用域。
具体请去:https://juejin.cn/post/6844904083707396109#heading-42
注意
1.函数的作用域在函数定义的时候就决定了,而不是函数调用的时候才决定的
2.this指调用函数所处的环境(二者不要混淆)
3.作用域可以一层一层往外找;this则是按着原形链去访问它父级对象