js函数的调用方式以及apply, call, bind用法总结

一、函数4种调用的方式

  • 1.函数模式
  • 2.方法模式
  • 3.构造函数模式
  • 4.上下文模式(也有叫apply模式)

apply, call, bind用法

在JavaScript 中,call、apply 和 bind 是 Function 对象自带的三个方法,这三个方法的主要作用是改变函数调用过程中的 this 指向

1. apply(thisArgs[,args[]])

  • 第一个参数指定函数体内this对象的指向
    thisArgs 的取值有以下4种情况:
    • 不传,或者传null,undefined非严格模式下 函数中的 this 指向 window 对象。 严格模式不传undefined 函数中this指向undefined传入null函数中this指向null
    • 传递另一个函数的函数名,函数中的 this 指向这个函数的引用
    • 传递字符串、数值或布尔类型等基础类型,非严格模式函数中的 this 指向其对应的包装对象,如 StringNumberBoolean严格模式,指向传入的值
    • 传递一个对象,函数中的 this 指向这个对象
  • 第二个参数为一个带下标的集合,可以是数组或类数组,apply方法把这个集合中的元素作为参数传递给被调用的函数
var func = function(a, b, c) {
  console.log([a, b, c]); // [1,2,3]
}
func.apply(null, [1,2,3])

apply 和 call 的唯一区别是第二个参数的传递方式不同,apply 的第二个参数必须是一个数组,而 call 允许传递一个参数列表。值得你注意的是,虽然 apply 接收的是一个参数数组,但在传递给调用函数时,却是以参数列表的形式传递,我们看个简单的例子:

function b(x,y,z){
    console.log(x,y,z);
}
 
b.apply(null,[1,2,3]); // 1 2 3

2. call(thisArgs [,args...])

该方法可以传递一个thisArgs参数和一个参数列表,thisArgs 指定了函数在运行期的调用者,也就是函数中的 this 对象,而参数列表会被传入调用函数中。
thisArgs 的取值有以下4种情况:

  • 不传,或者传null,undefined非严格模式下 函数中的 this 指向 window 对象。 严格模式不传undefined 函数中this指向undefined传入null函数中this指向null
  • 传递另一个函数的函数名,函数中的 this 指向这个函数的引用
  • 传递字符串、数值或布尔类型等基础类型,非严格模式函数中的 this 指向其对应的包装对象,如 StringNumberBoolean严格模式,指向传入的值
  • 传递一个对象,函数中的 this 指向这个对象
function a(){
    console.log(this); //输出函数a中的this对象
}
function b(){} //定义函数b
 
var obj = {name:'onepixel'}; //定义对象obj
// 严格模式
a.call(); //undefined
a.call(null); //null
a.call(undefined);//undefined
a.call(1); //1
a.call(''); // ''
a.call(true); //true
a.call(b);// function b(){}
a.call(obj); //Object
 // 非严格模式
a.call(); //window
a.call(null); //window
a.call(undefined);//window
a.call(1); //Number
a.call(''); //String
a.call(true); //Boolean
a.call(b);// function b(){}
a.call(obj); //Object

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

var func = function( a, b, c ){
  alert ( this === window );    // 输出true
};
func.apply( null, [ 1, 2, 3 ] );

但如果是在严格模式下,函数体内的this还是为null:

var func = function( a, b, c ){    
  "use strict";    
  alert ( this === null );     // 输出true
}
func.apply( null, [ 1, 2, 3 ] );

有时候我们使用call或者apply的目的不在于指定this指向,而是另有用途,比如借用其他对象的方法。
那么我们可以传入null来代替某个具体的对象:
Math.max.apply( null, [ 1, 2, 5, 3, 4 ] ) // 输出:5

call和apply的用途

确定函数内部this指向
var obj1={
  name: '李小龙'
}
var obj2={
  name: '萧薰'
}
window.name = 'window'
var getName = function(){
  console.log(this.name)
};
getName(); //输出:window
getName.call(obj1); //输出:李小龙
getName.call(obj2); //输出:萧薰

当执行getName.call( obj1 )这句代码时,getName函数体内的this就指向obj1对象

  • this 错误的情况
document.getElementById( 'div1' ).onclick = function(){    
  alert( this.id );            // 输出:div1    
  var func = function(){       
    alert ( this.id );        // 输出:undefined    
  }    
  func();
};
  • 修正this
document.getElementById( 'div1' ).onclick = function(){    
  var func = function(){        
    alert ( this.id );        // 输出:div1    
  }    
  func.call( this );
};

3. bind(thisArgs [,args...])

bind是ES5 新增的一个方法,它的传参和call类似,但又和 call/apply 有着显著的不同,即调用 call 或 apply 都会自动执行对应的函数,而 bind 不会执行对应的函数,只是返回了对函数的引用。粗略一看,bind 似乎比call/apply 要落后一些,那ES5为什么还要引入bind 呢?

其实,ES5引入 bind 的真正目的是为了弥补 call/apply 的不足,由于 call/apply 会对目标函数自动执行,从而导致它无法在事件绑定函数中使用,因为事件绑定函数不需要我们手动执行,它是在事件被触发时由JS 内部自动执行的。而 bind 在实现改变函数 this 的同时又不会自动执行目标函数,因此可以完美的解决上述问题,看一个例子就能明白:

var obj = {name:'onepixel'};
/**
 * 给document添加click事件监听,并绑定onClick函数
 * 通过bind方法设置onClick的this为obj,并传递参数p1,p2
 */
document.addEventListener('click',onClick.bind(obj,'p1','p2'),false);
 
//当点击网页时触发并执行
function onClick(a,b){
    console.log(
            this.name, //onepixel
            a, //p1
            b  //p2
    )
}

参考JavaScript设计模式与开发实践 、 一像素 博客园

你可能感兴趣的:(js函数的调用方式以及apply, call, bind用法总结)