一、什么是this指针
简单来说,js中的this指针指向的是调用它的对象(下面各种例子读者可自行揣摩)
// 1、理解this指针
var name = "windowName";
function a() {
var name = "li";
console.log(this.name); // windowName
// ES5中 指向的是调用它的对象,
console.log(this); // Window {window: Window, self: Window, document: document, name: 'windowName', location: Location, …}
}
a(); // 没有调用者,所以this指向的默认对象就是window
var name = "windowName";
var a = {
name: "cherry",
func: function() {
console.log(this.name); // cherry this指向它的调用者a,所以是cherry
}
}
a.func();
var name = "windowName";
var a = {
name: "cherry",
func: function() {
console.log(this.name); // cherry this还是指向它的调用者a,不管前面有多少个调用,所以是cherry
}
}
window.a.func();
var name = "windowName";
var a = {
// name: "cherry",
func: function() {
console.log(this.name); // undefined this指向调用者a,只会在当前对象里找,但是没有name,所以undefined
}
}
window.a.func();
var name = "windowName";
var a = {
name: "cherry",
func: function() {
console.log(this.name); // windowName 这里的this永远指向它的调用者
}
}
var f = a.func; // 把这个函数付给了一个变量,通过这个变量执行(地址引用)
f(); // 这样执行是没有调用者的,默认指向window,所以就是windowName
var name = "windowName";
function func() {
var name = "cherry";
console.log(this); // Window {window: Window, self: Window, document: document, name: 'windowName', location: Location, …}
innerFunc(); // 这个函数也没有调用者
function innerFunc() {
console.log(this.name);
}
}
func(); // windowName 没有调用者 所以this就是window
二、如何改变指针的指向?
// 如何改变指针
var name = "windowName";
var a = {
name: "cherry",
func1: function() {
console.log('this.name :>> ', this.name);
},
func2: function() {
var _this = this;
// setTimeout 这是普通函数写法,没有调用者,所以this指向window
setTimeout(function() {
this.func1(); // this
}, 100)
// 改变指针指向
// 1、箭头函数,下面这个时候this指向的是a对象
setTimeout(() => {
this.func1(); // this
}, 100)
// 2、闭包
setTimeout(function() {
_this.func1(); // this
}, 100)
// 3、call、apply
// call--执行一个函数 函数名.call(作用域对象)---就是将函数放到特定的作用域对象中执行
setTimeout(function() {
_this.func1(); // this
}.call(a), 100) // 就是将函数放到特定的作用域对象中执行,这个时候this指向就是a
// call--执行一个函数 函数名.apply(作用域对象)---就是将函数放到特定的作用域对象中执行
setTimeout(function() {
_this.func1(); // this
}.call(a), 100) // 就是将函数放到特定的作用域对象中执行,这个时候this指向就是a
}
};
a.func2();
三、call、apply的区别
// call、apply的区别
var a = {
name: "cherry",
func: function(a, b) {
console.log('a+b :>> ', a + b);
}
}
var b = a.func;
// apply----第一个参数a:作用域对象,第二个参数--必须数组形式
b.apply(a, [1, 2]); // 3
// call----第一个参数a:作用域对象,第二个参数可以是多个
b.call(a, 1, 2); // 3
// bind可以绑定作用域,但不立即执行----此时c函数的作用域就是a
var c = b.bind(a, 1, 2); // 3
c();
四、call、apply实现原理
// call、apply是怎样实现的
Function.prototype.mycall = function(ctx) { // ctx----作用域对象
ctx = ctx || window; // 传参,有作用域就用,没有就window
ctx.func = this; // 添加一个属性 如: a.func = this; this==b ------ 在a这个函数里面添加了一个函数func,这个函数就是b函数
// console.log(arguments); // arguments是js内置对象----函数参数集合(可以理解为一个数组,这个数组里面装的就是[a,1,2])
// 取参数1,2
// [...arguments]--(将参数展开)--[a,1,2]----slice(1)--从下标为1的开始分割
let arg = [...arguments].slice(1);
// 执行b函数
let result = ctx.func(...arg);
return result;
}
b.mycall(a, 1, 2); // mycall的调用者是b,所以上面的this就是b