This指针
每一个方法或函数都会有一个this对象,this对象是方法(或函数)在执行时的那个环境,也可以说是这个函数在那个作用域下运行的。说的更通俗一点:this就相当于咱们平时说话时候说的“我”,“我家”的概念。就是说当一个方法在运行的时候,它是属于谁的。它在运行的时候它的家是谁家。
在 ES5 中,其实 this 的指向,始终坚持一个原理:this 永远指向最后调用它的那个对象
例1:对象的调用
var person = {
name: 'Demi',
describe: function () {
return '姓名:' + this.name;
}
};
console.log(person.describe()) // 姓名:Demi
上面代码中,this.name是在describe方法中调用,而describe方法所在的当前对象是person,因此this最后调用的那个对象就是person, this.name就是person.name
例2:对象赋值给另外一个对象调用
var A = {
name: 'Demi',
describe: function () {
return '姓名:' + this.name;
}
};
var B = {
name: 'dingding'
};
B.describe = A.describe;
console.log(B.describe()) // 姓名:dingding
上面代码中,A.describe属性被赋给B,于是B.describe就表示describe方法所在的当前对象是B,所以this.name就指向B.name
例3:函数调用
var name = "windowsName";
function a() {
var name = "Demi";
console.log(this.name); // windowsName
console.log("inner:" + this); // inner:[object Window]
}
a();
console.log("outer:" + this); // outer:[object Window]
上面代码中,this.name是在a()函数中调用, a()前面没有调用的对象,那么this会指向顶层对象Window,相当于window.a()
例4:this 永远指向最后调用它的那个对象,不会向上一个对象寻找未定义变量
var name = "windowsName";
var a = {
// name: "Demi",
fn: function () {
console.log(this.name); // undefined
}
}
window.a.fn();
上面代码中,最后调用fn()的对象是a, 所以this指向的是a对象,也就是说 fn 的内部的 this 是对象 a,而对象 a 中并没有对 name 进行定义,所以 log 的this.name的值是 undefined
例5:匿名函数this指向window
var obj = {
name: 'Demi',
times: [1, 2, 3],
print: function () {
this.times.forEach(function (n) {
console.log(this.name);
});
}
};
obj.print(); // 无输出
上面代码中,obj.print内部this.times的this是指向obj的,这个没有问题。但是,forEach方法的回调函数内部的this.time却是指向全局对象,导致没有办法取到值。
如何改变this指向
this的动态切换,固然为 JavaScript 创造了巨大的灵活性,但也使得编程变得困难和模糊。有时,需要把this固定下来,避免出现意想不到的情况。改变this指向有以下几种方法:
- 使用ES6箭头函数
- 在函数内部使用_this=this
- JavaScript 提供了call、apply、bind这三个方法来切换this的指向
- new实例化一个对象
箭头函数
this对象的指向是可变的,但是在箭头函数中,它是固定的。箭头函数体内的this对象,就是定义时所在的对象,而不是调用时所在的对象。
例5:通过箭头函数改变原来指向window的this
let name = "windowsName";
let a = () => {
let name = "Demi";
console.log(this.name); // Demi
console.log("inner:" + this); // inner:[object a]
}
a();
console.log("outer:" + this); // outer:[object Window]
上面代码中,原来是window调用a()函数,this指向的是window,将函数改成箭头函数,this指向定义时所在的对象,也就是说this.name指向a
在函数内部使用_this = this
那么这种方式应该是最简单的不会出错的方式了,我们是先将调用这个函数的对象保存在变量 _this中,然后在函数中都使用这个 _
this,这样 _this就不会改变了
var obj = {
name: 'Demi',
times: [1, 2, 3],
print: function () {
var _this = this
this.times.forEach(function (n) {
console.log(_this.name);
});
}
};
obj.print(); // Demi Demi Demi
Function.prototype.call()
函数实例的call
方法,可以指定函数内部this
的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。
使用格式:func.apply(thisValue, arg1, arg2, ...) call
的第一个参数就是this
所要指向的那个对象,后面的参数则是函数调用时所需的参数。this.Value为空、null、undefined,则默认传入全局对象。
var obj = {
name: 'Demi'
}
function a() {
console.log(this.name);
};
a.call(obj); // Demi
function add(a, b) {
return a + b;
}
add.call(this, 1, 2) // 3
Function.prototype.apply()
apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数,使用格式如下。
使用格式:func.apply(thisValue, [arg1, arg2, ...]) 第一个参数也是this
所要指向的那个对象,如果thisValue设为null
或undefined
,则默认传入全局对象。第二个参数则是一个数组,该数组的所有成员依次作为参数,传入原函数。原函数的参数,在call
方法中必须一个个添加,但是在apply
方法中,必须以数组形式添加。
function a(x, y) {
console.log(x + y);
};
a.call(null, 1, 1); // 2
a.call(null, [1, 1]); // 2
Function.prototype.bind()
bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。bind 是创建一个新的函数,我们必须要手动去调用它才会执行。
使用格式:func.apply(thisValue, arg1, arg2, ...) () 第一个参数就是this
所要指向的那个对象,后面的参数则是函数调用时所需的参数。this.Value为空、null、undefined,则默认传入全局对象。
var a = {
name: "Demi",
fn: function (a, b) {
console.log(a + b)
}
}
var b = a.fn;
b.bind(a, 1, 2)() // 3
使用构造函数调用函数
如果函数调用前使用了 new 关键字, 则是调用了构造函数。
这看起来就像创建了新的函数,但实际上 JavaScript 函数是重新创建的对象
// 构造函数:
function myFunction(arg1, arg2) {
this.firstName = arg1;
this.lastName = arg2;
}
// This creates a new object
var a = new myFunction("Ding", "Demi");
console.log(a.lastName); // 返回 "Demi"
new实例化过程
- 创建一个空对象 obj;
- 将新创建的空对象的隐式原型指向其构造函数的显示原型。
- 使用 call 改变 this 的指向
- 如果无返回值或者返回一个非对象值,则将 obj 返回作为新对象;如果返回值是一个新对象的话那么直接直接返回该对象。
所以我们可以看到,在 new 的过程中,我们是使用 call 改变了 this 的指向。
var a = new myFunction("Ding","Demi");
new myFunction{
var obj = {};
obj.__proto__ = myFunction.prototype;
var result = myFunction.call(obj,"Ding","Demi");
return typeof result === 'obj'? result : obj;
}
文章每周持续更新,可以微信搜索「 前端大集锦 」第一时间阅读,回复【视频】【书籍】领取200G视频资料和30本PDF书籍资料
网友评论