this理解
- this是指包含它的函数作为方法被调用时所属的对象
一、this的指向大致可以分为以下几种
注:this指向什么跟函数所处位置没有关系,跟函数被调用的方式有关系
- 默认绑定:作为普通函数独立调用(在这种模式下,this代表全局对象Global。)
function foo(){
console.log(this);
}
foo() //window
var obj = {
foo: function(){
console.log(this);
}
}
var bar = obj.foo
bar() //window
- 隐式绑定:作为对象的属性来调用(这时this就指这个上级对象)
function foo(){
console.log(this);
}
var obj = {
foo : foo
}
obj.foo(); //obj对象
var obj = {
foo: function(){
console.log(this);
}
}
var obj2 = {
name: '这是obj2',
bar: obj.foo
}
obj2.bar() //obj2对象
- 作为构造函数来调用(这时this指向Persion实例对象)
function Persion(){
this.name = "Jackie"
this.age = 21
this.show = function(){
console.log(this); //Persion实例对象
}
}
var p = new Persion();
p.show(); //在show方法中方法this,指向了p对象实例。
- 显示绑定:通过call与apply改变this的指向
注:call和apply传入参数方式不同
function sum(num1, num2, num3){
console.log(num1 + num2 + num3, this);
}
var obj = {
name: '这是obj'
}
sum.call(obj,20,50,70) //this指向obj对象
sum.apply(obj,[20,50,70]) //this指向obj对象
- 显示绑定:bind
默认绑定和显示绑定bind冲突:优先级最高(显示绑定)
function aaa(){
console.log(this);
}
var obj = {
name: '这是obj'
}
var newa = aaa.bind(obj)
newa() //此时显示绑定和默认绑定冲突,当前this指向obj对象,而不是默认绑定的window对象
二、this绑定优先级
- 默认绑定的优先级最低 foo()
- 显示绑定优先级高于隐式绑定 foo.call(obj) > obj.foo()
//call/apply优先级高于隐式绑定
var obj1 = {
name: 'obj1',
foo: function(){
console.log(this);
}
}
var obj2 = {
name: 'obj2'
}
obj1.foo.call(obj2); //this指向obj2对象
//bind优先级高于隐式绑定
function foo(){
console.log(this);
}
var obj = {
name: 'obj',
foo: foo.bind("abc")
}
obj.foo(); //this指向字符串abc
- new绑定优先级高于隐式绑定
var obj = {
name: 'obj',
foo: function(){
console.log(this);
}
}
var f = new obj.foo() //this指向foo函数
- new绑定优先级高于bind显示绑定
var obj = {
name: 'obj对象',
foo: function foo(){
console.log(this);
}
}
var a = obj.foo.bind("aaa")
var bar = new a() //this指向foo函数
结论:new绑定 > 显示绑定(call/apply/bind) > 隐式绑定(obj.foo()) > 默认绑定(独立函数调用)
附加:当apply/call/bind传入undefined/null时,自动将this绑定成全局对象
var obj = {
name: 'obj对象',
foo: function foo(){
console.log(this);
}
}
obj.foo.call(null) //window
obj.foo.apply(undefined) //window
var bar = obj.foo.bind(null)
bar() //window
三、ES6箭头函数(箭头函数不在前四个绑定规则生效)
- 当在setTimeout中传入的参数为函数时,函数内部的this才会指向window对象。
- 箭头函数本身不绑定this,当箭头函数中使用this时,会去找该函数的上层作用域的this
var obj = {
data: [],
getData: function(){
console.log(this); //obj对象
setTimeout(function(){
console.log(this); //window
})
setTimeout(console.log(this)) //obj对象
setTimeout(()=>console.log(this)) //obj对象
}
}
obj.getData() //obj对象、obj对象、window、obj对象
四、关于this面试题
var name = "window";
var person = {
name: "person",
sayName: function () {
console.log(this.name);
}
};
function sayName() {
var sss = person.sayName;
sss(); //window (默认绑定)
person.sayName(); //person (隐式绑定)
(person.sayName)(); //person (隐式绑定)
(b = person.sayName)(); //window (默认绑定)
}
sayName();
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(隐式绑定)
person1.foo1.call(person2); //person2(显示绑定)
person1.foo2(); //window(箭头函数不绑定this,则找该函数的上层作用域全局)
person1.foo2.call(person2); //window(依然是找上层作用域)
person1.foo3()(); //window(默认绑定->独立函数调用)
person1.foo3.call(person2)(); //window(默认绑定->独立函数调用)先执行person1.foo3.call(person2),再进行函数独立调用
person1.foo3().call(person2); //person2(显示绑定)
person1.foo4()(); //person1,箭头函数本身没有this,此时this指向上层作用域的this,又因为上层是隐式调用,所以此时this指向person1
person1.foo4.call(person2)(); //person2(将person1.foo4的作用域this绑定到person2作用域)
person1.foo4().call(person2); //person1(先执行person1.foo4(),箭头函数不绑定this所以即便call(person2),还是会去找上层作用域this)
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(隐式绑定)
person1.foo1.call(person2) //person2(显示绑定)
person1.foo2() //person1(隐式绑定)
person1.foo2.call(person2) //person1(箭头函数本身没有this,即便call(person2)还是去找上层作用域this)
person1.foo3()() //window(独立函数调用)
person1.foo3.call(person2)() //window(独立函数调用,相当于先执行person1.foo3.call(person2),后再独立调用这个函数)
person1.foo3().call(person2) //person2(显示绑定)
person1.foo4()() //person1(默认绑定->独立函数调用)
person1.foo4.call(person2)() //person2(隐式绑定)
person1.foo4().call(person2) //person1(箭头函数this指向上层作用域)
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()() //window(独立函数调用)
person1.obj.foo1.call(person2)() //window(独立函数调用)
person1.obj.foo1().call(person2) //person2(隐式绑定)
person1.obj.foo2()() //obj(箭头函数不绑定this,该箭头函数上层作用域this.name为obj)
person1.obj.foo2.call(person2)() //person2(隐式绑定)
person1.obj.foo2().call(person2) //obj(箭头函数不绑定this,该箭头函数上层作用域this.name为obj)