this指向
在js中有一个很重要但是又比较难的点,那就是this的指向问题,this在函数内部定义的时候指向是不确定的,只有在调用的时候才能知道。
1.函数直接调用
我们写一个代码,首先在声明一个变量a,值为1,,然后再写一个函数,内部同样声明一个a,值为2,在函数内部输出this.a。
var a = 1;
function fun() {
var a = 2
console.log(this.a);
}
fun()
结果会是1,this是谁调用就指向谁,那么此时的函数其实是由window对象,也就是全局对象调用,因此this指向window,输出window下的a,所以是1
2.对象内的函数调用
var a = 1;
var obj = {
a: 2,
fun: function() {
var a = 3
console.log(this.a);
}
}
obj.fun()
此时是obj来调用的,this指向obj,因此输出2
我们看一道题:
var a = 1;
var obj = {
a: 2,
fun: function() {
var a = 3
console.log(this.a);
}
}
var b = {
fun1: function(fun) {
fun()
}
}
b.fun1(obj.fun)
首先我们整理一下代码:
obj.fun实际上就是:
function fun() {
var a = 3
console.log(this.a);
}
然后把这个函数传入函数fun1,实际上最后函数fun1调用的时候等价于:
var b = {
fun1: function() {
(function fun() {
var a = 3
console.log(this.a);
})()
}
}
b.fun1()
传进去的函数fun实际上是由window调用的,因此还是输出全局下的a,值为1
3.构造函数里的this
function Obj(name, age) {
this.name = name;
this.age = age
}
var a = new Obj('Jack', 18)
console.log(a);
在构造函数中我们也需要用到this关键字,构造函数是用new关键字来调用的,而在构造函数调用时,new会先创建一个对象,而this的指向在此时会被new关键字改变,此时this会指向新创建的对象。这也是构造函数实例对象的关键。
this指向的改变
1.call方法
var a = 1;
var obj = {
a: 2
}
function fun() {
console.log(this.a);
}
fun();//1
fun.call(window)//1
fun.call(obj)//2
call方法的第一个参数就是this要指向的对象,但是当函数需要传参的时候,call方法,只能把这些参数一个一个的传进去
// fun.call(obj,参数1,参数2......)
var a = 1;
var obj = {
a: 2
}
function fun(a1, a2) {
console.log(this.a, a1, a2);
}
fun.call(obj, '33', '12')
首先让this指向obj,然后把实参传进函数,使用call方法改变this指向时会直接调用函数
2.apply
var a = 1;
var obj = {
a: 2
}
function fun() {
console.log(this.a);
}
fun(); //1
fun.apply(window) //1
fun.apply(obj) //2
apply方法在使用的时候跟call方法类似,唯一不同的就是apply方法只能传两个参数,在函数需要传参的时候,参数是以数组的方法传入的
// fun.apply[参数1,参数2],......)
var a = 1;
var obj = {
a: 2
}
function fun(a1, a2) {
console.log(this.a, a1, a2);
}
fun.apply(obj, ['33', '12'])
同样,使用apply方法改变this指向也会直接调用函数
3.bind
bind方法也可以改变this的指向,call和apply方法都会直接调用函数,但是我们有时候不希望函数被直接调用,就可以使用bind方法
但是要注意,bind方法是直接创建一个新的函数,然后让this指向这个新函数的第一个参数
// fun.bind(obj,参数1,参数2......)
var a = 1;
var obj = {
a: 2
}
function fun(a1, a2) {
console.log(this.a, a1, a2);
}
var fun1 = fun.bind(obj, '33', '12')
fun1()
console.log(fun1);
浏览器看一下结果
bind方法的传参方式跟call类似,第一个是this要指向的对象,然后是要传入的参数,但是bind的返回值就是一个全新的函数,因此需要变量接受,然后调用新函数