JavaScript高级this绑定绑定优先级相关面试题与箭头函数
Posted karshey
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript高级this绑定绑定优先级相关面试题与箭头函数相关的知识,希望对你有一定的参考价值。
文章目录
this绑定
- 函数在调用时,javascript会默认给this绑定一个值
- this的绑定与定义的位置无关
- this的绑定与调用方式以及调用的位置有关
- this在运行时被绑定
this有四种绑定规则:
- 默认绑定
- 隐式绑定
- 显示绑定
- new绑定
默认绑定
独立函数调用时使用默认绑定。 如:
- 普通的函数独立被调用
function foo()
console.log(this);
foo();
这里控制台输出:Window
- 函数定义在对象中,但是独立调用
function foo()
console.log(this);
var obj=
bar:function()
console.log(this);
var temp=obj.bar
temp()
这里控制台输出:Window
- 严格模式下
'use strict'
,独立调用的函数中的this指向的是undefined
隐式绑定
通过某个对象进行调用。 如:
function foo()
console.log(this);
var obj =
bar: foo
obj.bar()//这里是obj这个对象调用的bar
控制台输出:bar: ƒ
这里this就绑定到了obj这个对象上,就是bar: ƒ
注意:隐式绑定有一个前提条件
- 必须在调用的对象内部有一个对函数的引用(比如一个属性)
- 如果没有这个引用,在调用时就会报找不到该函数的错误
- 正是通过这个引用,间接的将this绑定到了这个对象上
如果我们不希望在对象内部包含这个函数的引用,同时又希望这个对象进行强制调用,则可以用显示绑定。
显示绑定
通过call或apply绑定this对象我们成为显示绑定。
需求:调用foo且this指向obj
var obj =
name:"name"
function foo()
console.log(this);
this.name="name";
完成需求:
foo.call(obj)
注意,是foo.call(obj)
不是foo().call(obj)
:foo()
是foo函数调用后的返回值,是undefined
。
foo().call(obj)
就是undefined.call(obj)
.
控制台:name: 'name'
——它就是obj
如果call()传递的对象是如"123",123这种,则会自动转换成其包装类对象。如果传递的对象是undefined,则this会绑定到window。
实际上,显示绑定有两个函数:apply和call。
function foo()
console.log(this);
foo()
foo.apply("apply")
foo.call("call")
控制台:
Window window: Window, self: Window, document: document, name: '', location: Location, …
String 'apply'
String 'call'
apply的参数:
- 第一个参数:绑定this
- 第二个参数:传入额外的参数,以数组的形式
call的参数:
- 第一个参数:绑定this
- 参数列表:后续的参数以多参数的形式传递
bind
如果我们希望一个函数总是显示地绑定到一个对象上,我们可以使用bind
方法。
function foo()
console.log(this);
var obj=name:"name"
var bar=foo.bind(obj)
bar()//this->obj
控制台:name: 'name'
bind的其他参数:
- 第一个参数:绑定this
- 参数列表:后续的参数以多参数的形式传递
new绑定
JavaScript中的函数可以当作一个类的构造函数来使用,也就是使用new
关键字。
new
关键字会做的事情:
- 创建新的空对象
- 将this指向空对象
- 执行函数体中的代码
- 没有显示返回这个非空对象时,默认返回这个对象
function foo()
console.log(this);
this.name="name";
new foo()
控制台:foo
翻译:new了一个foo(),this指向它,然后指向foo()函数里的代码。
绑定优先级
- 默认绑定的优先级最低
- 显式绑定>隐式绑定
- bind>call和apply
- new绑定>隐式绑定
- new绑定>bind
- new、call、apply不能一起使用,无可比性
总体优先级从大到小:
- new
- bind
- apply/call
- 隐式
- 默认
this规则之外:忽略显示绑定
- 在显示绑定中传入null或undefined,那么显示绑定会被忽略,使用默认绑定规则
- 创建一个函数的间接引用,使用默认绑定规则,如:
var obj1=
name:"obj1",
foo:function()
console.log(this);
var obj2=
name:"obj2"
;
obj2.foo=obj1.foo
obj2.foo()
控制台:name: 'obj2', foo: ƒ
是obj2.
但如果把最后两句改成:
(obj2.foo=obj1.foo)()
则:Window
因为(obj2.foo=obj1.foo)
的结果是foo
函数,因此整个式子可以看作是一个独立函数的调用。因此this指向Window
。
箭头函数
箭头函数,即arrow function,它:
- 不会绑定this,arguments属性
- 不能作为构造函数来使用(不能和new一起使用)
写法:
- 参数()
- 函数体
//之前的方式
var foo1 = function (name, age)
console.log("函数体");
console.log(name + " " + age);
//箭头函数:最完整的写法
var foo2 = (name, age) =>
console.log("箭头函数函数体");
console.log(name + " " + age);
一个示例:
var names = ["123", "345","456"]
names.forEach((item, index, arr) =>
console.log(item, index, arr)
)
控制台:
js.html:60 123 0 (3) ['123', '345', '456']
js.html:60 345 1 (3) ['123', '345', '456']
js.html:60 456 2 (3) ['123', '345', '456']
箭头函数的编写优化
- 只有一个参数()可以省略
- 函数体中只有一行代码可以省略,且这行代码的返回值会是整个函数的返回值(所以一行代码不能带return)
- 如果函数体只有一个返回对象,那么这个对象要加上()(不然会以为是执行体)
如:
var names = ["123", "345", "456"]
names.forEach(item =>
console.log(item)
)
控制台:
123
345
456
如:
var nums = [1, 2, 3, 4, 5]
var newnums = nums.filter(item => item % 2 === 0)
console.log(newnums);
控制台:
[2, 4]
箭头函数中的this使用
箭头函数中没有this:所以会往全局中找this,因此这里的this指向window
var bar = ()=>console.log("bar",this)
bar()//window
bar.apply("AAA")//window
箭头函数的查找规则
箭头函数中没有this,当箭头函数内部开始调用this时,js引擎就从作用域由里到外的找含有this指向的作用域。
如:
第一层,bar函数,是箭头函数,没有this,往外找;
第二层,foo函数,有this,指向obj;
var obj =
name:"obj",
foo:function()
var bar = ()=>
console.log("bar",this);
return bar;
如:
第一层,bar函数,是箭头函数,没有this,往外找;
第二层,foo函数,是箭头函数,没有this,往外找;
第三层,也就是全局,this指向window。(注意,对象里没有自己的作用域!)
var obj =
name:"obj",
foo:()=>
var bar =()=>
console.log("bar:",this);
return bar;
相关面试题
问这些this都指向?
1
var name="window";
var person=
name:"person",
sayName:function()
console.log(this.name);
;
function sayName()
var temp=person.sayName;
temp();
person.sayName();
(person.sayName)();
(b=person.sayName)();
sayName();
控制台:
window
person
person
window
解析:
- 独立函数调用,默认绑定,所以是window
- 隐式绑定
- 隐式绑定,跟上面一样。加一个括号就是优先获取到这个方法的意思。
- 简介函数引用(指路:this规则之外),
b=person.sayName
得到的就是一个函数,这里就是一个独立函数引用,所以是window
2
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);
控制台:
person1
person2
window
window
window
window
person2
person1
person2
person1
解析:要找到上层作用域里的this指向的是什么
- 隐式绑定
- 显示绑定
- 箭头函数无this,会去上层作用域找this,会找到window
- 同上
- 默认绑定,这里person1.foo3()就是拿到一个函数,person1.foo3()();是独立函数调用
- 同上,person1.foo3.call(person2)这里相当于直接拿到一个函数
- 显示绑定
- 隐式绑定的是person1,且里面的箭头函数无this,所以它会向外找this,找到的就是隐式绑定的person1
- 显示绑定的是person2,且里面的箭头函数无this,所以它会向外找this,找到的就是显示绑定的person2
- 隐式绑定
3
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)
控制台:
person1
person2
person1
person1
window
window
person2
person1
person2
person1
解析:
- 隐式绑定
- 显示绑定
- 箭头函数无this,因此找上层作用域的this,是person1(注意,这里的上层是Person函数)
- 同上,无this所以call无效
- 独立函数调用,默认绑定
- 同上,因为返回的是函数
- 显示绑定
- 独立函数调用,但调用的是箭头函数,箭头函数里无this,所以往外层找,找到的this是person1(隐式绑定)
- 显示绑定了person2,独立函数调用,但调用的是箭头函数,箭头函数里无this,所以往外层找,找到的this是person2
- 对箭头函数call无效,箭头函数里无this,所以往外层找,找到的this是person1
4
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)
控制台:
window
window
person2
obj
person2
obj
解析:
- 独立函数调用,默认绑定
- 独立函数调用,默认绑定——就算绑定了返回的也是函数
- 显示绑定
- 独立函数调用,但是无this,往上找,找到的是obj(obj在调用,隐式绑定)
- 去上层作用域里找,找到了显示绑定的person2
- call但是无意义,去上层作用域里找,找到的是obj
参考资料
coderwhy的视频
JavaScript高级 |彻底搞清this指向问题
JavaScript高级 |如何玩转箭头函数?
以上是关于JavaScript高级this绑定绑定优先级相关面试题与箭头函数的主要内容,如果未能解决你的问题,请参考以下文章