函数call() apply() bind() 三个方法目的相同: 改变函数中this的指向;三者在使用上存在差别,这致使三者有各类的应用场景:call()、apply()更为接近;html
相同点: call、apply、bind 第一个参数:this指向的对象(上下文),以后的参数为要传入的变量;数组
不一样点:app
var obj = {name:"Hello , function !"} function fun(){ console.log(this.name) } fun.call(obj) fun.apply(obj) fun.bind(obj)() //1.call、apply 使用接近,只是参数传递形式不一样 //2.call、apply 会当即执行函数;bind返回一个绑定obj的函数,不会当即执行(这点很重要!决定了bind的使用场景)
一,call()函数
1.用法:oop
call( [obj , [arg1,[arg2,...]]] )this
2.第一个参数obj的取值:spa
2.1).不传、null、undefined,函数的this指向window对象(在不严格模式下,this指向window;严格模式下,对应的this指向undefined、null、undefined)设计
function A(){console.log(this)} // 不严格模式下 A.call() // window A.call(null) // window A.call(undefined) // window function B(){"use strict"; console.log(this)} // 严格模式下 B.call() // undefined B.call(null) // null B.call(undefined) // undefined
2.2).传入数值、字符串、布尔值等基础类型,this指向对应的包装类型Number、String、Booleancode
2.3).传入函数名,this指向这个函数的引用htm
A.call( B ) // function B(){"use strict"; console.log(this) }
2.4).传入对象,this指向这个对象(最经常使用)
3.使用场景
3.1)一个容易犯错的例子
function add(x,y){ console.log( x+y ) } function sub(x,y){ console.log( x-y ) } add.call( sub, 8, 6 ) // 14 // 执行的是add函数,只不过add函数中this指向了sub函数
3.2)改变this的指向(经常使用)
var name = "hi!" var obj = {name:"hello!"} function A(){console.log(this.name)} A() // "hi!" A.call(obj) // "hello!"
3.3) 继承(经常使用)
function Person(id,name){ this.id = id; this.name = name; } function Student(id,name,grade,score){ Person.call(this,id,name) // 使用call()完成继承 this.grade = grade; this.score = score; } var stu = new Student('123','Jame','grade 2','98')
二,apply()
apply 和 call 使用基本相同,仅仅是参数传递不一样;call() 参数一个一个传;apply() 传递的是一个数组;
当传递参数个数已知时,使用call();若是参数不定,使用apply();
用法:
apply(obj,[arg1,arg2,...])
例题:
1.自定义log()函数,模拟console.log()函数;
分析:
1.1)console.log()函数,能够传递多个不一样类型的参数;经过自定义函数简单模拟console.log()能够这样作:
function log(arg){ console.log(arg) }
可是这样有个问题,只能传递一个参数,多个参数怎么办?
2.1) 因为多个参数就涉及到arguments对象,能够将log()改装成:
function log(){ console.log(arguments) }
这样还不行,console.log()会把arguments直接打印出来;
此时的arguments仅仅是console.log()函数中arguments对象的arguments[0];
若是想按照console.log()方式打印出来,必须将log()的arguments传值给console.log()函数的arguments对象;
正确方式以下:
// 只能使用apply function log(){ console.log.apply(console,arguments) } // 不能使用call函数,不然console.log()函数仍然会把 log()函数的arguments对象当成自身arguments[0]
三,bind()
函数绑定bind是ES5中新增的,IE6,7,8不支持;
bind绑定对象后不会当即执行,而是返回一个函数,以便特定状况下使用;这个技巧大量的用在回调函数、事件处理程序中;
1.事件处理程序中的this指向
DOM元素绑定事件后,事件处理程序中this默认状况下指向DOM元素;(IE8 默认指向window)
若是要使用别的对象中的方法,就必须使用bind()进行绑定
var handler = { name: "Hello world", handClick: function(event){ console.log( this.name ) } } document.getElementById('demo').addEventListener('click',handler.handClick); // 输出undefined,DOM绑定后的函数handClick中的this指向DOM元素;而this中不包含name
若是要想输出handler对象中的name,须要使用bind绑定该对象
document.addEventListener('click',handler.handClick.bind(handler))
2.回调函数中的this指向,常见的定时器
在定时器中,回调函数中的this默认指向window;
常常须要在定时器的回调函数中使用别的对象中的属性、方法,解决的办法有三种:1.新建一个中间变量 2.bind绑定 3.ES6中的箭头函数 ,最经常使用的是bind、ES6箭头函数
var obj = { msg:"Hello world", getInfo: function(){ setTimeout(function(){console.log(this.msg)},0) // this->window ,输出undefined // 1.使用中间变量that var that = this; setTimeout(function(){console.log(that.msg),0}) // that->obj,输出"Hello world" // 2.使用bind setTimeout(function(){console.log(that.msg).bind(obj),0}) // this->obj,输出"Hello world" // 2.使用ES6箭头函数,箭头函数中的this指向定义这个函数时所在的对象 setTimeout(() => {console.log(this.msg)},0}) // this->obj,输出"Hello world" } }
bind函数的应用场景基本就是回调函数、事件处理程序;
如何实现bind()函数?(绑定一个上下文,并返回绑定了这个上下文的函数)
function bind(fn,context){ return function(){ return fn.apply(context,arguments) } }
参考:(感谢如下文档)
[1] 理解call、apply、bind[2] 《JavaScript高级程序设计(第3版)》