一、结论
- this指向什么,跟函数所处的位置没有关系,跟函数被调用的方式有关系
// 同一个函数的三种不同调用方式
function foo() {
console.log(this);
}
// 1. 直接调用
foo(); //window
// 2. 通过对象调用
const obj = {
foo: foo,
};
obj.foo(); //obj
// 3. 通过call调用
foo.call({ name: "123" }); //{ name: "123" }对象
二、this的绑定规则
- 默认绑定:独立函数调用
function foo() {
console.log(this);
}
foo(); //window
const obj = {
name: "obj",
foo: foo,
};
const bar = obj.foo;
bar(); //window
- 隐式绑定:通过某个对象进行调用的
// 隐式绑定
//1. 案例一
function foo() {
console.log(this);
}
const obj = {
name: "foo",
foo: foo,
};
obj.foo(); //obj
// 案例二
const obj1 = {
foo: function () {
console.log(this);
},
};
const obj2 = {
name: "obj2",
foo: obj1.foo,
};
obj2.foo(); //obj2
- 显式绑定:通过call、apply、bind调用
function foo(num1, num2) {
console.log(this, num1, num2);
}
const obj = {
name: "obj",
};
// call、apply、bind可以指定this的绑定对象,
// call和apply之间的区别在于传递参数的形式不同
// bind返回一个新的函数
foo.call(obj, 10, 20); //obj
foo.apply(obj, [10, 20]); //obj
const bar = foo.bind(obj, 10, 20);
bar(); //obj
- new绑定:js中的构造函数可以通过new方式来调用
/**
* 使用new关键字来调用函数,会执行如下的操作
* 1. 创建一个新对象
* 2. 新对象的__proto__属性指向构造函数的prototype
* 3. this指向这个新对象,指向构造函数中的代码
* 4. 如果函数没有返回其他对象,返回这个新对象
*/
function Person(name, age) {
this.name = name;
this.age = age;
console.log(this);
}
const p1 = new Person("name1", 18); //p1
const p2 = new Person("name2", 19); //p2
三、this绑定规则的优先级
new绑定>显式绑定>隐式绑定>默认绑定
- 默认绑定优先级最低
- 显式绑定高于隐式绑定
// 显式绑定高于隐式绑定
const obj = {
name: "obj",
foo: function () {
console.log(this);
},
};
obj.foo.call("abc"); //String{'abc}
obj.foo.apply("abc"); //String{'abc}
- new绑定高于隐式绑定
const obj = {
name: "obj",
foo: function () {
console.log(this);
},
};
const instance = new obj.foo(); //instance
- new绑定高于显式绑定
// new关键字不能和apply/apply一起使用
function foo() {
console.log(this);
}
const bar = foo.bind("aaa");
const obj = new bar(); //foo{}
四、箭头函数
- 箭头函数不绑定this,this指向上层作用域
- 箭头函数不能通过new调用
手写call、apply、bind函数
//call函数的实现
Function.prototype.myCall = function (thisArg, ...args) {
let fn = this;
if (thisArg === undefined || thisArg === null) {
thisArg = window;
} else {
thisArg = Object(thisArg);
}
thisArg.fn = fn;
const result = thisArg.fn(...args);
delete thisArg.fn;
return result;
};
//apply函数的实现
Function.prototype.myApply = function (thisArg, args) {
let fn = this;
if (thisArg === undefined || thisArg === null) {
thisArg = window;
} else {
thisArg = Object(thisArg);
}
thisArg.fn = fn;
if (!args) {
args = [];
}
const result = thisArg.fn(...args);
delete thisArg.fn;
return result;
};
//bind函数的实现
Function.prototype.myBind = function (thisArg, ...args1) {
let fn = this;
if (thisArg === undefined || thisArg === null) {
thisArg = window;
} else {
thisArg = Object(thisArg);
}
thisArg.fn = fn;
return function (...args2) {
const result = thisArg.fn(...args1, ...args2);
delete thisArg.fn;
return result;
};
};