文章源于 coderwhy ”js高级视频“ 总结
在大多情况下,this出现在函数中。this指向什么,跟函数定义的位置无关,跟函数调用方式有关(绑定规则相关)。
function foo(){
console.log(this);
}
var obj = {
foo: foo
}
//不同的调用方式this的指向不同,不同的调用方式对应着不同的绑定规则
foo();//window
obj.foo();//obj
foo.call("123");//String{"abc"}
显示绑定(bind>call/apply) > 隐式绑定 > 默认绑定
function fn() {
console.log(this);
}
fn.bind(123).apply(321);
new 绑定 > 隐式绑定 > 默认绑定
new 绑定 > 显示绑定(通过bind绑定this的函数,可以被new关键字改变this指向)
function Fn(){
console.log(this);
}
fn.bind("132");
var obj = new Fn();
new关键字不能和call/apply一起使用,因为new会主动调用函数,call/apply也会主动调用函数,这样会产生冲突报错
绑定优先级:new 绑定 > 显示绑定 > 隐式绑定 > 默认绑定
apply/call/bind:当传入null/undefined时,自动将this绑定成全局对象
function fn(){
console.log(this);
}
fn.apply(null);
fn.apply(undefined);
var obj1 = {
foo: function(){
console.log(this);
}
}
var obj2 = {}
;(obj2.bar = obj1.foo)()//括号中包含赋值表达式,属于独立函数调用,是默认绑定,指向window
简写一:当参数只有一个,可以省略括号
简写二:当函数体只有一行,可以省略大括号,并且会将这一行代码的返回值return
var nums = [0, 1, 2, 3, 4, 5];
var result = nums
.filter(item => item % 2 === 0)
.map(item => item * 10)
.reduce((preVal, curVal) => preVal + curVal, 0);
console.log(result);
简写三:如果只有一个行,且需要返回一个对象,那么要将对象用括号包裹。因为省略"{}“后,不知道将对象的”{}"如何解析
var foo = () => ({ name: "foo", age: 18 });//这样解析时会将对象当作一个整体
箭头函数不遵循this的四种标准规则,箭头函数内部没有绑定this,也不能通过call/apply/bind绑定this,箭头函数的this指向根据外层作用域决定
var obj = {
getData() {
setTimeout(function () {
console.log(this);
}, 200);
},
};
//setTimeout中的函数属于独立调用,所以指向的是window
//如果想让this指向obj对象,setTimeout中使用箭头函数
obj.getData();
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)(); //包含赋值表达式,属于间接函数引用
}
sayName();
答案:window(默认绑定)、person(隐式绑定)、person(隐式绑定)、window(间接函数引用)
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);
答案解析:
person1.foo1(); //person1:隐式绑定
person1.foo1.call(person2); //person2:显示绑定
person1.foo2();//window:箭头函数的this指向上层作用域的this
person1.foo2.call(person2);//window:箭头函数的this指向上层作用域的this,且不能改变箭头函数指向
person1.foo3()();//window:先执行person1.foo3(),然后拿到返回的函数再调用,属于独立调用,所以指向window
person1.foo3.call(person2)();//window:先执行person1.foo3.call(person2),拿到返回的函数再调用,属于独立调用
person1.foo3().call(person2);//person2:先执行person1.foo3(),拿到返回的函数通过call调用this指向了person2
person1.foo4()(); //person1:拿到返回的箭头函数后,箭头函数没有this,根据上层作用域决定,上层foo4函数指向的是person1对象(foo4是被person1直接调用的),所以内部箭头函数也指向peroson1
person1.foo4.call(person2)(); //person2:给foo4绑定this为person2,箭头函数调用this指向上层作用域,上层foo4的this被显示绑定为了person2,那么内部的箭头函数也是指向person2
person1.foo4().call(person2); //person1:call调用箭头函数,依然去上一层找,所以依然是person1
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.foo1() //person1
person1.foo1.call(person2) //person2
person1.foo2() //person1:箭头函数,指向上层作用域的this,上层作用域是“Person构造函数”
person1.foo2.call(person2) //person1::箭头函数,指向上层作用域的this,不能被显示绑定
person1.foo3()() //window:拿到返回的函数后调用,属于独立调用
person1.foo3.call(person2)() //window:拿到返回的函数后调用,属于独立调用
person1.foo3().call(person2) //person2:通过call显示绑定
person1.foo4()() //person1:返回的箭头函数去上层作用域找,上层foo的this指向person1
person1.foo4.call(person2)()//person2:返回的箭头函数去上层作用域找,上层this通过call指向了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()()
person1.obj.foo1.call(person2)()
person1.obj.foo1().call(person2)
person1.obj.foo2()()
person1.obj.foo2.call(person2)()
person1.obj.foo2().call(person2)
答案与解析:
person1.obj.foo1()() //window:独立调用
person1.obj.foo1.call(person2)() //window:独立调用
person1.obj.foo1().call(person2) //person2:call显示绑定
person1.obj.foo2()() //obj:返回的是箭头函数,this由上层作用域foo2函数决定,foo2的this指向obj(foo2是被obj直接调用的),所以返回的箭头函数this也是指向obj
person1.obj.foo2.call(person2)()//person2:箭头函数上层作用域this被call指向person2,所以箭头函数也是指向person2
person1.obj.foo2().call(person2)//obj:箭头函数this不能被显示绑定