this的绑定规则及优先级
在 Javascript 中,this指向的绑定规则有以下四种:
- 默认绑定(非严格模式下,this指向window,严格模式下,this指向undefined)
- 隐式绑定(如果函数调用时,前面存在调养它的对象,那么this就会隐式绑定到这个对象上)
- 显示绑定(函数通过 call()、apply()、bind()调用,this指向被绑定的对象)
- new 绑定(函数被new 调用,this指向由new新构造出来的这个对象)
绑定规则的优先级:new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定
function test(){
this.a = '111'
}
let obj = {
a:'bbb',
fn(){
console.log(this)
}
}
function scope(){
test() // 默认绑定
obj.fn() // 隐式绑定
test.call(obj) // 显示绑定
new test() // new绑定
}
const Bar = test.bind(obj);
console.log(obj.a,'---',bar.a) // 'bbb --- 111'
// new绑定改变了显式绑定中指定的this(obj)
// 显示绑定 > new 绑定
this的几种情况
全局作用域下的this指向window,严格模式下为undefined
function windowScope(){
console.log(this) // window or undefined
}
如果给元素的事件行为绑定函数,那么函数中的this指向当前被绑定的那个元素
document.body.onclick = function(){
console.log(this) // body
}
函数中的this,要看函数执行前有没有(调用者),如果有的话,调用者是谁,this就指向谁,如果没有调用者,指向window。自执行函数中的this永远指向window
let fn = function() {
console.log(this.name)
}
let obj = {name:'amy',fn};
fn(); // window.name
obj.fn(); //
obj.name
定时器中函数的this指向window
setTimeout(function(){
console.log(this) // window
},0)
构造函数中的this指向当前当前的实例
- call、apply、bind 可以改变函数的this指向
- 箭头函数中没有this,如果输出this,就会输出箭头函数定义时所在的作用域中的this
- 括号表达式也有可能改变this,括号内只有一个项不会,两个或多个的话this指向window
this相关面试题
题1:
var num = 10
const obj = {num: 20}
obj.fn = (function (num) {
this.num = num * 3
num++
return function (n) {
this.num += n
num++
console.log(num)
}
})(obj.num)
var fn = obj.fn
fn(5)
obj.fn(10)
console.log(num, obj.num)
题2:
var a = {
name:"zhang",
sayName:function(){
console.log("this.name="+this.name);
}
};
var name = "ling";
function sayName(){
var sss = a.sayName;
sss(); //this.name = ?
a.sayName(); //this.name = ?
(a.sayName)(); //this.name = ?
(b = a.sayName)();//this.name = ?
}
sayName();
题3:
var obj = {
a: 1,
foo: function (b) {
b = b || this.a
return function (c) {
console.log(this.a + b + c)
}
}
}
var a = 2
var obj2 = { a: 3 }
obj.foo(a).call(obj2, 1)
obj.foo.call(obj2)(1)
题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)