this
到底指向谁? 箭头函数中的this
还能使用吗? 如果能使用又要怎么使用呢? 与普通函数的this
指向一致吗?
this
到底指向谁?首先,定义一个函数:
三种不同的调用方式,this的指向也会不同!
直接调用 foo() // window{}
通过对象调用 1 2 3 var obj = { name: 'name' } obj.foo = foo obj.foo(); // Object{} (obj这个对象)
call/apply/bind foo.apply(“abc”) // String {‘abc’}
结论:
函数在调用时,js会默认给this绑定一个值 ; this的绑定跟它**定义的位置(编写的位置)**没有关系; this的绑定与调用方式以及调用的位置有关; this是在运行时被绑定的。 this
的绑定规则默认绑定 foo() // window{}
var bar = obj.foo bar() // window{}
严格模式 下,独立调用的函数中的this
指向undefined
1 2 3 4 <script > "use strict" ... </script >
function test(fn) {
fn()
}
test(obj.foo) // window{}
即独立调用函数时(非严格模式下)this
指向window
!
隐式绑定 一般是通过对象 来发起调用。
显式绑定 1 2 foo.call (obj) foo.apply (obj)
这两种形式的显示绑定区别不大,不会像隐式绑定那样在obj上面添加foo:foo,但是foo的this就指向了obj; 另外,这种形式一般将this绑定在对象身上,如果foo.call(‘abc’),那么也会默认将’abc’创建为对应的包装类型,这里也就是String
对象; 如果是绑定在了undefined
这种没有对应包装类型的对象身上,那么this就会默认指向window
call / apply函数说明 1 2 3 function test (name, age ) { console .log ('参数:' , name, age); }
作用:都可以调取函数并绑定this,传递参数方式不同
apply(obj,[argumentsArray])
obj
是指this指向的对象;
argumentsArray
是指函数的参数,必须要放在数组 中进行传递;
1 2 test.apply ('apply' , ['chenber' , 18 ])
<font style="color:#DF2A3F;">call(obj,arg1,arg2,...)</font>
obj
是指this指向的对象;
arg1,arg2,...
是指函数的参数列表。
1 2 test.call ('call' , 'chender' , 18 )
bind 1 2 3 4 5 6 var bar = test.bind ('bind' )bar () var bar = test.call ('call' , 'chender' , 18 ) bar ()
bind
是绑定(怪异)函数
,是返回绑定过对象的函数,那么在执行的时候this只会指向绑定好的对象;
而call
和apply
都是直接执行函数,没有返回值 。
1 2 3 var bar = test.call ('call' , 'chender' , 18 )bar () bar ()
❗️❗️❗️此时,会不会有疑问?(bar()函数单独调用,this不应该指向window吗?)
这里就涉及到了this绑定的优先级 了!
默认绑定优先级最低 显式绑定 > 隐式绑定 1 2 3 4 5 6 7 8 9 10 11 12 13 var obj = { name : 'chenber' , age : 18 , test : test } obj.test .apply ('apply' , ['1' , 19 ]) var test1 = obj.test .bind ('bind' , 'chenber' , 18 )test1 ()
new 绑定 > 隐式绑定 1 2 3 4 5 6 7 8 9 10 var obj = { name : 'chenber' , foo : function ( ) { console .log ('foo:' , this ); console .log ('foo:' , this === obj); } } new obj.foo ()
new > 显式(bind) ❗️new
和apply
/ call
不可以一起使用,所以没有可比性
new
和bind
可以一起使用
1 2 3 4 5 6 function test ( ) { console .log ('test' , this ); } var testFN = test.bind ('abc' ) new testFN ()
new绑定 使用new关键字来调用函数是,会执行如下的操作:
创建一个全新的对象; 这个新对象会被执行prototype连接: 这个新对象会绑定到函数调用的this上(this的绑定在这个步骤完成); 如果函数没有返回其他对象,表达式会返回这个新对象: 总结(优先级从高到低):
new bind apply / call 隐式 默认绑定 内置函数的调用绑定 内置函数的this指向需要根据一些经验
获取
setTimeOut() 1 2 3 setTimeOut (()=> { console .log ('this' , this ) },1000 )
按钮的点击监听 1 2 3 4 5 6 7 8 9 10 var btn = document .querySelector ('button' ) btn.onclick = function ( ) { console .log ('btn' , this ); } btn.addEventListener ("click" , () => { console .log ('btn' , this ); }) btn.addEventListener ("click" , () => { console .log ('btn' , this ); })
forEach forEach(function(){}, {})
forEach的两个参数:
回调函数 回调函数的this绑定对象 1 2 3 4 5 6 7 8 const names = ["abc" , "abc" , "abc" , "abc" , "abc" ]names.forEach (function (item ) { console .log ('forEach' , this ); }) names.forEach (function (item ) { console .log ('forEach' , this ); }, "cba" )
this
绑定之外的规则如果在使用显式绑定时传入null
或者undefined
,那么就会使用默认绑定规则 1 2 foo.apply (null ) foo.apply (undefined )
严格模式差异:在严格模式下,绑定null/undefined时会直接使用传入值,this会指向null或undefined本身。
间接函数引用(知道就行,一般不会出现) 1 2 var obj2 = {};(obj2.foo = obj.foo )()
箭头函数(补充) 箭头函数是 es6
新增的一种函数的声明方法。 1 2 3 const foo = (name,age )=>{ console .log ("=>" ) }
❗️注:
- 箭头函数不会绑定`this` 和 `arguments`(有新的属性进行代替)属性;
- 箭头函数不能作为构造函数来使用(会抛出错误)
箭头函数的简写只有一个参数时 可省略() 函数体只有一行语句时,可省略{},但是不能带return 关键字 如果执行体只有返回一个对象,那么需要给这个对象加上() 箭头函数中的 this
使用 箭头函数的作用域没有 this
! 但是箭头函数中this
会向寻找上层作用域中的this
,直至找到全局this->window
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const test = ( ) => { console .log ('this' , this ); } test () var test1 = test.bind ('abc' )test1 () var obj = { name : 'chenber' , foo : () => { console .log ('this' , this ); } } obj.foo () const test2 = obj.foo .bind ('abc' )test2 ()
应用实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 function request (url, callbackFn ) { const results = { code : 200 , msg : '成功' , data : null } callbackFn (results) } var obj = { results : {}, getData : function ( ) { request ('/test' , (res ) => { this .results = res }) } } obj.getData ()
1.6 相关面试题 面试题一 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var name = 'window' var person = { name : 'person' , sayName : function ( ) { console .log (this .name ) } } function sayName ( ) { var sss = person.sayName ; sss (); person.sayName (); (person.sayName )(); (b = person.sayName )() }
面试题二 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 var name = 'window' var person1 = { name : 'person1' , foo1 : function ( ) { console .log (this .name ) }, foo2 : () => console .log (this .name ), foo3 : function ( ) { return function ( ) { console .log (this .name ) } }, foo4 : function ( ) { return () => { console .log (this .name ) } } } var person2 = { name : 'person2' } person1.foo1 (); person1.foo1 .call (person2); person1.foo2 (); person1.foo2 .call (person2); person1.foo3 ()(); person1.foo3 .call (person2)(); person1.foo3 ().call (person2); person1.foo4 ()(); person1.foo4 .call (person2)(); person1.foo4 ().call (person2);
面试题三 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 var name = 'window' function Person (name ) { this .name = name this .foo1 = function ( ) { console .log (this .name ) } this .foo2 = () => console .log (this .name ) this .foo3 = function ( ) { return function ( ) { console .log (this .name ) } } this .foo4 = function ( ) { return () => { console .log (this .name ) } } } var person1 = new Person ('person1' )var person2 = new Person ('person2' )person1.foo1 (); person1.foo1 .call (person2); person1.foo2 (); person1.foo2 .call (person2); person1.foo3 ()(); person1.foo3 .call (person2)(); person1.foo3 ().call (person2); person1.foo4 ()(); person1.foo4 .call (person2)(); person1.foo4 ().call (person2);
面试题四 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 var name = 'window' function Person (name ) { this .name = name this .obj = { name : 'obj' , foo1 : function ( ) { return function ( ) { console .log (this .name ) } }, foo2 : function ( ) { return () => { console .log (this .name ) } } } } var person1 = new Person ('person1' )var person2 = new Person ('person2' )person1.obj .foo1 ()() person1.obj .foo1 .call (person2)() person1.obj .foo1 ().call (person2) person1.obj .foo2 ()() person1.obj .foo2 .call (person2)() person1.obj .foo2 ().call (person2)