一 普通的this指向
1 在函数中this指向window全局对象,在严格模式下为undefined
2 在对象中调用this 指向对象本身
3 箭头函数的this 指向是在创建时就确定的 不会被改变,由于箭头函数的特性是捕获外层作用域的 this,这里的外层作用域是全局作用域,因此箭头函数中的this指向的是全局对象window
4 构造函数的this指向 当使用new关键字调用构造函数时,构造函数内部的this关键字指向新创建的对象实例。
function ftn() {
console.log(this);
}
ftn(); //Window
console.log(this); //Window
var obj = {
name: "WeTab",
printName: function () {
console.log(this.name);
},
ftn: () => {
console.log(this);
},
};
obj.printName(); //WeTab
obj.ftn(); //window
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHello = function () {
console.log(
"Hello, my name is " +
this.name +
" and I am " +
this.age +
" years old."
);
};
}
const person1 = new Person("Alice", 30);
person1.sayHello(); // 输出:Hello, my name is Alice and I am 30 years old.
二 简单练习题解析
1 函数内的this指向
function ftn(val){
this.count +=val
}
ftn.count=0
console.log(ftn(1));//undefined
因为ftn函数的this 指向的是全局对象window 而不是函数本身 所以this.count为undefined
2 对象中的this指向
const obj={
x:1,
print:()=>{
console.log(this.x);
},
print1(){
console.log(this.x);
},
print2:function(){
console.log(this.x);
},
print3:function(){
console.log(this.x);
}.bind(this)
}
obj.print() //undefined
obj.print1() // 1
obj.print2() // 1
obj.print3() //undefined
print是一个箭头函数,箭头函数的特性是捕获外层作用域的this值。在这里,箭头函数 print中的 this 指向的是全局对象 window,因此 this.x 为 undefined。
print1是一个常规函数,常规函数中的 this 会根据调用方式的不同而变化。在这里,print1是作为对象obj的方法调用,因此 this 指向的是 obj对象,所以 this.x 的值为 1
。
print2也是一个常规函数,效果和print1 一样, this.x 的值为 1
。
print3是一个常规函数,并且使用了bind(
this )
方法来强制绑定 this 。然而,在对象字面量中无法通过 bind来改变 this 的指向,因此 this.x 为 undefined。
三 改变this指向的3种方法 call、apply、bind 的区别
1 call和apply改变this指向的同时会直接进行调用,而bind改变this指向的时候不会进行直接调用
function greet() {
console.log(`Hello, ${this.name}!`);
}
const person = { name: "Alice" };
greet.call(person); // 输出 "Hello, Alice!"
greet.apply(person); // 输出 "Hello, Alice!"
greet.bind(person)//
const ftn=greet.bind(person)
ftn() //输出 "Hello, Alice!"
2 call和bind都是以单个参数的形式进行传参,而apply是以数组的形式进行传参
function greet(greeting, punctuation) {
console.log(`${greeting},${punctuation},${this.name}`);
}
const person = { name: "!" };
greet.call(person,"Hello",'call')// 输出 "Hello,call,!"
greet.apply(person,["Hello",'apply']) 输出 "Hello,apply,!"
const boundGreet = greet.bind(person, "Hello",'bind');
boundGreet(); // 输出 "Hello,bind,!"
3 综合练习题
var name='hello'
function Ftn(name){
this.name=name,
this.fool=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 ftn1=new Ftn('ftn1')
var ftn2=new Ftn('ftn2')
ftn1.fool() //ftn1
ftn1.fool.call(ftn2) //ftn2
console.log('foo2');
ftn1.foo2() //ftn1
ftn1.foo2.call(ftn2) //ftn1
console.log('foo3');
ftn1.foo3()() //hello
ftn1.foo3.call(ftn2)() //hello
ftn1.foo3().call(ftn2) //ftn2
console.log('foo4');
ftn1.foo4()() //ftn1
ftn1.foo4.call(ftn2)() //ftn2
ftn1.foo4().call(ftn2) //ftn1
解析:
1 ftn1.fool(): 输出ftn1,因为fool方法直接在ftn1对象上调用的所以直接打印ftn1对象上的name
2 ftn1.fool.call(ftn2): 输出 ftn2,因为通过使用call,将fool方法的中的this指向改变为ftn2对象,所以打印的是ftn2对象的 name 。
3 ftn1.foo2(): 输出ftn1,因为foo2方法直接在ftn1对象上调用的所以直接打印ftn1对象上的name
4 ftn1.foo2.call(ftn2):输出ftn1,因为箭头函数不能改变this指向,因此无论如何调用,都会以定义时的this指向为准,所以还是打印ftn1对象上的name
5 ftn1.foo3()():输出hello 是因为return返回后的function 函数中的this 指向的是全局对象,所以最后输出的是全局对象下的name 。 这里注意 如果是let声明变量 是无法添加在全局对象上的, 如果是let name=hello 输出为“”
6 ftn1.foo3.call(ftn2)():输出hello 这里call 改变的是第一个function指向而不是return后的this指向,所以return 后的function 还是指向全局对象
7 ftn1.foo3().call(ftn2):输出ftn2,这里是使用call改变了return后的this指向 使其this指向ftn2 所以输出的是ftn2对象上的name
8 ftn1.foo4()():输出ftn1 因为foo4 返回的是箭头函数,箭头函数的this指向声明时的对象,所以输出为fth1上的name
9ftn1.foo4.call(ftn2)():输出ftn2 因为call 改变了function函数的指向 而不是要改变return回来的箭头函数
10 ftn1.foo4().call(ftn2):输出ftn1,因为return返回的时箭头函数 ,箭头函数的this指向无法被改变,所以依然打印ftn1上的name