this指针、call和apply的区别

this指针

this是Javascript语言的一个关键字。

它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。比如,

function test(){
    this.x = 1;
}

随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对象

下面分四种情况,详细讨论this的用法。

情况一:纯粹的函数调用

这是函数的最通常用法,属于全局性调用,因此this就代表全局对象Global。

请看下面这段代码,它的运行结果是1。

function test(){
    this.x = 1;
    alert(this.x);
}

test(); // 1

为了证明this就是全局对象,我对代码做一些改变:

var x = 1;
function test(){
    alert(this.x);
}

test(); // 1

运行结果还是1。再变一下:

var x = 1;
function test(){
    this.x = 0;
}

test();
alert(x); //0

作为对象方法的调用

函数还可以作为某个对象的方法调用,这时this就指这个上级对象。

function test(){
    alert(this.x);
}

var o = {};
o.x = 1;
o.m = test;
o.m(); // 1

情况三 作为构造函数调用

所谓构造函数,就是通过这个函数生成一个新对象(object)。这时,this就指这个新对象。

function test(){
    this.x = 1;
}

var o = new test();

alert(o.x); // 1

运行结果为1。为了表明这时this不是全局对象,我对代码做一些改变:

var x = 2;
function test(){
    this.x = 1;
}

var o = new test();

alert(x); //2

运行结果为2,表明全局变量x的值根本没变。

apply调用

apply()是函数对象的一个方法,它的作用是改变函数的调用对象,它的第一个参数就表示改变后的调用这个函数的对象。因此,this指的就是这第一个参数。

var x = 0;
function test(){
    alert(this.x);
}

var o={};
o.x = 1;
o.m = test;
o.m.apply(); //0

apply()的参数为空时,默认调用全局对象。因此,这时的运行结果为0,证明this指的是全局对象。

如果把最后一行代码修改为

o.m.apply(o); //1

运行结果就变成了1,证明了这时this代表的是对象o。

call 和 apply

callapply 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向

callapply二者的作用完全一样,只是接受参数的方式不太一样

apply 方法定义

Function.apply(obj,args)
参数描述
obj这个对象将代替Function类里this对象
args这个是数组或类数组,apply方法把这个集合中的元素作为参数传递给被调用的函数。

call 方法定义

Function.call(obj,arg1,arg2,arg3...)
参数描述
obj这个对象将代替Function类里this对象
args一个参数列表

注意

在非严格模式下当我们第一个参数传递为nullundefined时,函数体内的this会指向默认的宿主对象,在浏览器中则是window

var test = function(){
  console.log(this===window);
}
test.apply(null);//true
test.call(undefined);//true

call 和 apply 用法

1. "劫持"别人的方法

此时foo中的logName方法将被bar引用,this指向了bar

var foo = {
  name:"mingming",
  logName:function(){
    console.log(this.name);
  }
}
var bar={
  name:"xiaowang"
};
foo.logName.call(bar);//xiaowang

2. 实现继承

function Animal(name){   
  this.name = name;   
  this.showName = function(){   
    console.log(this.name);   
  }   
}   
 
function Cat(name){  
  Animal.call(this, name);  
}   
 
var cat = new Cat("Black Cat");   
cat.showName(); //Black Cat

在实际开发中,经常会遇到this指向被不经意改变的场景。

有一个局部的fun方法,fun被作为普通函数调用时,fun内部的this指向了window,但我们往往是想让它指向该#test节点,见如下代码:

window.id="window";
document.querySelector('#test').onclick = function(){
  console.log(this.id);//test
  var fun = function(){
    console.log(this.id);
  }
  fun();//window
}

使用call,apply我们就可以轻松的解决这种问题了

window.id="window";
document.querySelector('#test').onclick = function(){
  console.log(this.id);//test
  var fun = function(){
    console.log(this.id);
  }
  fun.call(this);//test
}

当然你也可以这样做,不过在ECMAScript 5的strict模式下,这种情况下的this已经被规定为不会指向全局对象,而是undefined:

window.id="window";
document.querySelector('#test').onclick = function(){
  var that = this;
  console.log(this.id);//test
  var fun = function(){
    console.log(that.id);
  }
  fun();//test
}

ECMAScript 5strict模式下,这种情况下的this已经被规定为不会指向全局对象,而是undefined

function func(){
  "use strict"
  alert ( this );  // 输出:undefined
}
func();