函数内部的this指向以及call(),apply(),bind()的梳理

函数内部this的指向,是调用函数的时候确定的.调用方式的不同决定this指向不同.

调用方式 普通函数调用 构造函数调用 对象方法调用 事件绑定方法 定时器函数 立即执行函数
this指向 window 实例对象,原型对象方法也指向实例 方法所属对象 绑定事件对象 window window

 

call(),bind(),apply()的作用与其分别的写法和作用机制 

var person = {
   FirstName:‘Bill‘,
   LastName:‘Gates‘,
   FullName:function(){
       return this.FirstName +"" +this.LastName;   
     }      
} 
person.fullName();

FullName属性是一个方法.person对象是该方法的拥有者.
FullName属于person对象.

  call(方法是预定义的JS方法.它可以用来调用所有者对象作为参数的方法.

      通过call(),您能使用属于另一个对象的方法.

       举个来自W3的例子:调用上面person的FullName(),并用于person1;

var person = {
    fullName: function() {
        return this.firstName + " " + this.lastName;
    }
}
var person1 = {
    firstName:"Bill",
    lastName: "Gates",
}
var person2 = {
    firstName:"Steve",
    lastName: "Jobs",
}
person.fullName.call(person1);  // 将返回 "Bill Gates"

  或者调用 person 的 fullName 方法,并用于 person2;

var person = {
    fullName: function() {
        return this.firstName + " " + this.lastName;
    }
}
var person1 = {
    firstName:"John",
    lastName: "Doe",
}
var person2 = {
    firstName:"Steve",
    lastName: "Jobs",
}
person.fullName.call(person2);  // 将返回 "Steve Jobs"

  然后通常在实际运用中,call()方法都会带上参数.

var person = {
  fullName: function(city, country) {
    return this.firstName + " " + this.lastName + "," + city + "," + country;
  }
}
var person1 = {
  firstName:"LiLei",
  lastName: "HanMeimei"
}
person.fullName.call(person1, "ShangHai", "China");//"Lilei HanMeimei,ShangHai,China."//指向对象.call(被指向对象,参数1,参数2)&&this原本对象.call(this接受对象,参数1,参数2);

  个人理解是,call()函数,就是用于跨函数调用属性值,无论这个属性是函数是字符串还是其他形式,然后返回结果.

然后是比较相似的apply(),apply()和call()属性差不多,不同之处在于call()分别接受参数,apply()接受以数组形式的参数.

所以更适合接受参数为数组的调用环境,如果内部参数不是数组形式,就会报错.

同样的例子:

var person = {
    fullName: function() {
        return this.firstName + " " + this.lastName;
    }
}
var person1 = {
    firstName: "Bill",
    lastName: "Gates",
}
person.fullName.apply(person1);  // 将返回 "Bill Gates"

var person = {
  fullName: function(city, country) {
    return this.firstName + " " + this.lastName + "," + city + "," + country;
  }
}
var person1 = {
  firstName:"John",
  lastName: "Doe"
}
person.fullName.apply(person1, ["Oslo", "Norway"]);//apply()的调用方法
person.fullName.call(person1, "Oslo", "Norway");//call()的调用方法

 

 在W3中,关于apply()的具体应用有提到Math.max搭配的用法.涉及到利用数学内置对象求最大值.

var arr = [1,66,3,99,4];
var max = Math.max.apply(null,arr);//也可以写成Math.max.apply(Math,arr);
console.log(max);//99
//这里的null是不改变this指向
//apply要求非this指向的参数为数组形式,其实并没有直接限制,而是在处理时进行检查.

  Math.max能调用apply(),说明其他函数也能调用apply()并对数组进行增删改查升降序处理.

最后一个bind(),MDN的描述中是这样的:

bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。

同时DEMO举出了下面这个案例:

var module = {
  x: 42,
  getX: function() {
    return this.x;
  }
}

var unboundGetX = module.getX;
console.log(unboundGetX()); // 这个函数事实上是没有获取到的,中间的赋值过程其实并不成立
// expected output: undefined

var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());//当绑定上一个函数时,this指向被bind()改变,于是赋值过程就成立了
// expected output: 42

 

  是不是感觉和前面的call()很像,感觉就一样?我们接着往下看MDN的描述.

首先是语法:

function.bind(thisArg[,arg1[,arg2[, ...]]])

  thisArg是调用bind绑定的函数,this参数传递给目标函数的值.如果简单理解,就是输出方对象想绑定的输入方函数对象.

  arg1和arg2是目标函数(输入方)被调用时,预先添加到绑定函数的参数.

返回值返回一个原函数的拷贝,也就是说返回的是原函数改变this之后产生的新函数.指向并拥有指定的this值和初始参数.

举个简单例子:

var o = {
    name:‘andy‘
};
function fn(a,b){
  console.log(this);  
  console.log(a+b);
};
var f = fn.bind(o,1,2);
f();//{name:‘andy‘},3;

  但上面都是基本的应用,实际中的常用环境更复杂一些.以常用的短信验证码发送按钮举例:

var btn = document.querySelector(‘button‘);
btn.onclick = function(){
      this.disabled = true;//这个this指向的是btn这个按钮
      var that = this;
      setTimeout(function(){
          that.disabled = false;//定时器函数里面的this指向的是window对象,所以用that
     },3000)
}   

如果用bind,就可以用this接着这样用:
var btn = document.querySelector(‘button‘);
btn.onclick = function(){
 this.disabled = true;//这个this指向的是btn这个按钮
 setTimeout(function(){
  this.disabled = false;
 }.bind(this),3000);//此时this指向btn
}
多按钮的写法:
var btns = document.querySelectorAll(‘button‘);
for(var i=0;i<btns.length;i++){
  btns[i].onclick = fuction(){
    this.disabled = true;
setTimeout(function(){
      this.disabled = false;
    }.bind(this),60000);
}
}

总结一下.

call(),apply(),bind().相同点都是能改变函数内部的this指向.

区别点:

1.call和apply会调用函数,并且改变函数内部this指向;

2.call与apply传递的参数不一样,call传递参数aru1,aru2,apply必须以数组形式接受参数;

3.bind不会调用函数内部的this指向,但是会拷贝从而改变指向;

 

 

 

函数内部的this指向以及call(),apply(),bind()的梳理

上一篇:appium遇到常见问题


下一篇:【原】iOS开发进阶(唐巧)读书笔记(二)