javascript中的this、 call() 和 apply()

1:this

   javascript中的this总是指向一个对象的,至于是指向哪一个对象,是运行时基于函数的执行环境的动态绑定的,尔非函数被声明时的环境;

  this的指向可以分为四类:

  •   作为对象的方法调用
  •   作为普通函数调用
  •   构造器调用
  •   Function.prototype.call()和Function.prototype.apply()
   1.1:作为对象的方法调用:

   当函数作为对象的方法被调用时,this指向该对象

//obj对象
  var obj={
   name:name;
   getName:function(){
   concole.log(this===obj);  //输出true
  console.log(this.name);     //输出name
  }
};
obj.getName();
   1.2作为普通函数调用:

     当函数不作为对象的属性被调用时,也就是以普通函数方式,this指向全局对象,在浏览器的javascript中,全局对象指的是winows对象

window.name=‘globalName’;   //声明全局对象name的属性

var getName=function(){
   return this.name;
}

console.log(getName());        //输出globalName;



window.name='globalName';   //声明全局对象name的属性

var obj={
    name:'myObjName',
    getName:function(){
    return this.name;
},
}

var myobj=obj.getName;
console.log(myobj());             //输出globalName;
 1.3构造器调用:

             javascript没有类,可以从构造器中创建对象,也提供了new运算符调用构造器。大部分javascript函数都可以当做构造器使用,构造器的外表和普通函数并没有什么两样,区别就是被调用的方式,即使用new运算符创建对象时,就是将函数当做构造器调用。当用new运算符调用函数时,该函数总会返回一个对象,此时,构造器里的this指向返回的这个对象。

var myClass=function(){
   this.name='classname';
};

var obj=new myClass();
console.log(obj.name);    //输出classname

             但,如果构造器显式地返回了一个object类型的对象,那么此函数将返回这个object类型的对象,而不是函数本身所定义的对象,例如:

var myClass=function(){
 
 this.name='classname';
   return{
    name:'lihe'
    };
};

var obj=new myClass();
console.log(obj.name);        //输出lihe

            而,如果构造器不显式地返回任何数据,或返回一个非对象类型的数据,就不会造成上述情形。

var myClass=function(){

this.name='classname';
return 'lihe';
};

var obj=new myClass();
console.log(obj.name);      //输出classname

1.4.Function.prototype.call 或 Function.prototype.apply调用

           跟普通函数调用相比,用 Function.prototype.call 或 Function.prototype.apply 可以动态地改变传入函数的this

var A={
name:'classnameA',
getName:function(){
   return this.name;
},
};


var B={
name:'classnameB',
};

console.log(A.getName());                //classnameA
console.log(A.getName.call(B));     //classnameB 

       丢失的this:

            当this的指向,与我们期待的不同时,就会出现undefined情况

var  obj={
  name:'classname',
  getName:function(){
   return this.name
},
};

//作为对象的方法引用,指向obj对象
console.log(obj.getName());   //输出classname

//作为普通函数调用,指向全局对象window,name属性还没定义
var getName2=obj.getName;
console.log(obj.getName2);      //输出undefined

 

   2   call和apply


 

Function原型的两个方法Function.prototype.call()  Function.prototype.apply()

call和apply区别:作用一样,传入参数形式不同

apply接受两个参数,第一个参数制定了函数体内this对象的指向,第二个函数为一个带下标的集合,这个集合可以是数组,也可以是类数组。apply方法把这个集合中的元素作为参数传递给被调用的函数。

var func = function(a, b, c){
  console.log([a, b, c]);  
};

func.apply(null, [1, 2, 3]);

call传入的参数数量不固定,第一个参数也是代表了函数体内的this指向,从第二个参数开始往后,每个参数依次被传入函数:

var func = function(a, b, c){
  console.log([a, b, c]); 
};

func.call(null, 1, 2, 3);

当使用call或apply的时候,如果我们传入的第一个参数为null,函数体内的this会指向默认的宿主对象,在浏览器中则是window:

var func = function(a, b, c){
  console.log(this);
};

func.apply(null, [1, 2, 3]);  //输出:window对象
func.call(null, 1, 2, 3);        //输出:window对象

 

3.call()  和apply()用途

  • 改变this指向

  • Function.prototype.bind

  • 借用其他对象的方法

3.1改变this指向:改变函数内部this的指向

var A = {
  name: 'nameA',
};

var B = {
  name: 'nameB',
};

window.name = 'nameWindow';

var getName = function(){
  console.log(this.name);
};

getName();             // 以普通函数调用,指向了window对象,输出nameWindow
getName.call(A);      // 改变了this的指向,指向了传入的对象,输出:nameA
getName.call(B);      // 改变了this的指向,指向了传入的对象,输出:nameB

3.2Function.prototype.bind

大部分高级浏览器都实现了内置的Function.prototype.bind,用来指定函数内部的this指向。若没有原生的Function.prototype.bind实现,可以通过模拟一个:

Function.prototype.bind = function(context){
  var self = this;  // 保存原函数
  return function(){  // 返回一个新的函数
      return self.apply(context, arguments);  // 执行新函数的时候,会把之前传入的context当作新函数体内的this
  }
};

var obj = {
 name: "objName"
};

var func = function(){
  console.log(this.name);  
}.bind(obj);

func();                     // 输出:objName

 

3.3借用其他对象的方法

  •     类数组对象的操作

想把arguments转成真正的数组的时候,可以借用Array.prototype.slice方法;

想往arguments中添加一个新的元素,可以借用Array.prototype.push:

想截去arguments列表中的头一个元素时,可以借用Array.prototype.shift方法。

(function(){
  Array.prototype.push.call(arguments, 3);
  console.log(arguments); // 输出:[1,2,3]
})(1, 2);

 

  •    借用构造函数,可以实现类似继承
var A = function(name){
 this.name = name;
};

var B = function(){  // 借用A的构造函数
  A.apply(this, arguments); 
};

B.prototype.getName = function(){
  return this.name;
};

var b = new B('baby');
console.log(b.getName());  // 输出:baby
posted @ 2015-11-08 00:04  阿狸先生  阅读(239)  评论(0编辑  收藏  举报