javascript——call()、apply()、bind()

说在前面

我们先来说一下三个方法的用途,即改变函数内部this指向。由此可见这三个方法都是函数的方法,且是非继承而来的方法。那么,先看一下函数的属性

函数属性

  • length:形参个数
  • name:函数名
  • prototype:对于引用类型而言,prototype保存了所有实例方法,在原型上定义的方法都是当前这个类的实例的公有方法;prototype属性不可枚举,for-in无效;
  • _proto_:把函数当做一个普通对象,指向Function这个类的原型
  • 函数的三种用法:
	function Fn() {      
	   var num = 500;         
	   this.x = 100;    
	}      
	Fn.prototype.getX = function () {     
	    console.log(this.x);          
	    this.a=101;         
	    console.log(this);    //Fn {x: 100, a: 101} _proto_:Object
	}     
	 Fn.aaa = 1000; 

	 var f = new Fn; //Fn作为一个类    
	 //f.getX();调用过后下面代码打印出101,不调用时,undefined    
	 console.log(f.a); // undefined
	 console.log(f.x);//100
	 console.log(f.num);//undefined  私有变量访问不到
	 console.log(f.aaa); //undefined aaa没有添加在原型上,不会被实例访问到     
  • 三角色
    • 普通函数:对于Fn而言,它本身是一个普通的函数,执行的时候会形成私有的作用域,然后进行形参赋值、预解析、代码执行、执行完成后内存销毁;
    • :它有自己的实例,f就是Fn作为类而产生的一个实例,也有一个叫做prototype 的属性是自己的原型,它的实例都可以指向自己的原型;
    • 普通对象:Fn和 var obj = {} 中的obj一样,就是一个普通的对象(所有的函数都是Function的实例),它作为对象可以有一些自己的私有属性,也可以通过__proto__找到Function.prototype;每个函数都有一个公共的 prototype —— Function,而这个原型自带有好几个属性和方法,其中就有 bind、call、apply 方法。

例子

看例子,我们可能以为这里的 this 指向 box,实际上此处 this 指向 window。

box.onclick = function(){
 function fn(){
   alert(this);
 }
 fn();
}

此时,我们一般会保存一下此处this值,如下

box.onclick = function(){
var that = this;
 function fn(){
   alert(that);
 }
 fn();
}

很明显,apply、call、bind也可以修复这个问题,如下:

box.onclick = function(){
 function fn(){
   alert(this);
 }
 fn.call(this);
}

call()、apply()、bind()区别

参数传递:

  • call()方法: 可以接受多个参数,第一个对象为新this对象 后面是形参列表,也就是说传递参数时要逐个列举出来。要用在js对象各方法相互调用的时候,使当前this实例指针保持一致,或者在特殊情况下需要改变this指针。如果没有提供Obj参数,那么 Global 对象被用作Obj。function.call(Obj,arr0,arr1,arr2,···);
  • apply()方法: 最多接受两个参数 新this对象和arr数组,即使第二个参数只有一个参数也要写进数组里。function.apply(Obj,[arr])
  • bind()方法:bind() 函数的参数跟 call() 一致,第一个参数也是绑定 this 的值,后面接受传递形参列表。function.bind(Obj,arr0,arr1,arr2,···);

看下面这个例子:

 function fn(num1, num2) {
     console.log(num1 + num2);     
     console.log(this);
 }
 fn.call(obj , 100 , 200);
 fn.apply(obj , [100, 200]);
 var tempFn = fn.bind(obj,100,200);
 tempFn();

call()挨个传值,apply传入数组,bind()挨个传值。call()和apply()都是立马调用对应的函数,而bind() 会生成一个新的函数,将绑定的this重新返回给新函数,然后在任何需要的地方调用。

基本使用

例子一

var arr = {1,2,3,4,5};
arr.pop();

arr这个实例首先原型上查找,实例中没有找到,然后通过原型链的查找机制找到Array.prototype上的pop方法,然后执行,删除arr最后一个元素并返回。

使用call后

var obj = {age:16};
function f(){
   console.log(this.age);
}
f();//this-->window
//obj.f();//Uncaught TypeError: obj.f is not a function
f.call(obj);//this-->{age: 16}    this.age-->16

首先寻找call方法,最后通过原型链在Function的原型中找到call方法,然后让call方法执行,在执行call方法的时候,f方法中的this变为第一个参数obj,最后执行f函数。

例子二
正常情况下,Math.max只能这样用

Math.max(3,2);

但是当你想传入一个数组时,就可以使用apply

var arr=[1,3,5,7,9];
Math.max.apply(null,arr);

或者想让伪数组调用数组方法

function(){
	[].push.call(arguments,3);
	console.log(arguments);//[1,2,3]
}
fn(1,2);

var arr = ['aabbc'];
console.log(''.indexOf.call(arr,'c')); //4  arr调用字符串的indexOf方法 与正常情况str.indexOf('b')相同

猜你喜欢

转载自blog.csdn.net/gaoshanyangzhi_1999/article/details/83118920