笔记-JS this指向
哪个对象调用函数,函数里面的this指向哪个对象。
普通函数调用
var name="tiger";
function Animal(){
var name="cat";
console.log(this.name);
}
Animal(); //输出结果:tiger
window对象调用Animal函数,this指向window对象。
let name="tiger";
function Animal(){
console.log(this.name);
}
Animal(); //输出结果:undefined
使用let声明,name是局部变量,window对象下没有name属性,所以输出结果为undefined。
对象函数调用
window.b=111;
let obj={
a:222,
fn:function(){
console.log(this.a); //输出结果:222
console.log(this.b); //输出结果:undefined
}
}
obj.fn();
obj对象调用函数,this指向obj对象。
let obj1={
a:111;
}
let obj2={
a:222;
fn:function(){
console.log(this.a);
}
}
obj1.fn=obj2.fn;
obj1.fn(); //输出结果:111
虽然obj1.fn是从obj2.fn赋值而来,但是调用函数的是obj1,所以this指向obj1.
构造函数调用
function Foo(){
console.log(this);
}
var bar=new Foo(); //输出结果:Foo实例,this就是bar
函数作为构造函数使用new调用时,this绑定的是新创建的构造函数的实例。
使用new调用构造函数时,会依次执行下面的操作:
1.创建一个新对象;
2.构造函数的prototype被赋值给这个新对象的__proto__;
3.将新对象赋值给当前的this;
4.执行构造函数;
5.如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象,如果返回的不是对象将会被忽略;
采用call、apply、bind改变this
var name="tiger";
function Animal(){
console.log(this.name);
}
Animal.call({name:"lion"}) //输出结果:lion
当使用call调用函数时,this被指向传入的对象。使用apply也可以达到相同的效果,但在实现上call和apply稍有不同。call方法接收的是参数列表,而apply方法接收的是一个参数数组。
func.call(thisArg,arg1,arg2,...);
func.apply(thisArg,[arg1,arg2,...]);
bind方法设置this为给定的值,并返回一个全新的函数,且在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项。
func.bind(thisArg[,arg1[,arg2[,...]]]
var food={
name:"汉堡",
price:"5块钱",
getPrice:function(place){
console.log(place+this.price);
}
}
food.getPrice("KFC") //输出结果:KFC5块钱
var getPrice1=food.getPrice.bind({name:"鸡腿",price:"7块钱"},"肯德基")
getPrice1();
采用apply实现bind原理
// ES5 方式
Function.prototype.bind = Function.prototype.bind || function() {
var self = this
var rest1 = Array.prototype.slice.call(arguments)
var context = rest1.shift()
return function() {
var rest2 = Array.prototype.slice.call(arguments)
return self.apply(context, rest1.concat(rest2))
}
}
// ES6 方式
Function.prototype.bind = Function.prototype.bind || function(...rest1) {
const self = this
const context = rest1.shift()
return function(...rest2) {
return self.apply(context, [...rest1, ...rest2])
}
}
如果将null或undefined作为this的绑定对象传入call、apply、bind,这些值在调用时会被忽略,实际应用的是默认规则。
var a="hello";
function foo(){
console.log(this,a);
}
foo.call(null); //输出结果:hello
this绑定的优先级:构造函数绑定(new绑定)>call、apply、bind绑定(显示绑定)>对象函数调用(隐式绑定)>普通函数调用(默认绑定)
箭头函数
箭头函数里面没有this,箭头函数里面的this是继承外面的环境。
let obj={
a:111,
fn:function(){
setTimeout(function(){console.log(this.a)});
}
};
obj.fn(); //输出结果:undefinded
fn()里面的this是指向obj,但是传给setTimeout的是普通函数,this指向的是window,window下面没有a,所以这里输出undefined.
换成箭头函数
let obj={
a:111,
fn:function(){
setTimeout(()=>{console.log(this.a)});
}
};
obj.fn(); //111
传给setTimeout的是箭头函数,然后箭头函数里面没有this,所以要向上层作用域查找,setTimeout的上层作用域是fn,而fn里面的this指向obj,所以setTimeout里面箭头函数的this指向obj