Function.prototype.call(this,arg1,arg2) Function.prototype.apply(this,[arg1,arg2]) Function.prototype.bind(this,arg1,arg2)
至于为何,看完这篇文章你就懂了:)javascript
若是你不懂什么是实例的话,请移步 深刻浅出面向对象和原型【概念篇1】、 深刻浅出面向对象和原型【概念篇2】
做用
返回值
返回值是你调用的方法的返回值,若该方法没有返回值,则返回undefined。
window.a = 1 function print(b, c) { console.log(this.a, b, c) } print(2, 3) // 1 2 3 print.call({a: -1}, -2, -3) // -1 -2 -3 print.apply({a: 0}, [-2, -3]) // 0 -2 -3
call()方法的做用和 apply() 方法是同样的,只有一个区别
call()方法接受的是若干个参数
apply()方法接受的是一个包含若干个参数的数组java
// 例子一 // Math.max()不接收数组的传递,咱们可使用apply方法 let answer = Math.max.apply(null, [2, 4, 3]) console.log(answer) // 4 // 注意下面三个等价 Math.max.apply(null, [2, 4, 3]) Math.max.call(null, 2, 4, 3) Math.max(2, 4, 3)
// 例子二 // 合并两个数组 let arr1 = ['parsnip', 'potato'] let arr2 = ['celery', 'beetroot'] // 将第二个数组融合进第一个数组 // 至关于 arr1.push('celery', 'beetroot'); Array.prototype.push.apply(arr1, arr2) // 注意!!!this的意思是谁调用了push这个方法 // 因此当 this = arr1 后 // 就成了 arr1 调用了 push方法 // 因此上述表达式等价于 arr1.push('celery', 'beetroot') console.log(arr1) // ['parsnip', 'potato', 'celery', 'beetroot']
例子二
中很是值得注意的就是arr2数组被拆开了,成了一个一个的参数segmentfault
因此,apply常常性的做用之一就是
将数组元素迭代为函数参数
// 例子三 Math.max.apply(null, [2, 4, 3]) // 完美运行 arr1.push.apply(null, arr2) // 报错 Uncaught TypeError: Array.prototype.push called on null or undefined // 说明 Math = { max: function (values) { // 没用到this值 } } Array.prototype.push = function (items) { // this -> 调用push方法的数组自己 // this为null的话,就是向null里push // Array.prototype.push called on null or undefined } // 下面三个值是彻底等价的,由于this值已是arr1 Array.prototype.push.apply(arr1, arr2) arr1.push.apply(arr1, arr2) arr2.push.apply(arr1, arr2)
function xx() { console.log(this) } xx.call('1') // ?? xx() // ??
若是答案和你想的不同,请移步 this总结【1】—— this概览
fun.bind(thisArg[, arg1[, arg2[, ...]]])
实例使用bind()方法后会返回一个新的函数【绑定函数】
而原函数为【目标函数】数组
我我的更喜欢用 新函数和 原函数来区分,由于新名词越多,理解上的困难越大
那么新函数被调用时会发生什么呢?
下面一句话务必记住
其实就是把原函数call/apply一下,并指定你传递的thisapp
function xx() { console.log(this) } let foo = xx.bind({'name':'jason'}) // foo —— 新函数【绑定函数】 // xx —— 原函数【目标函数】 foo() // 新函数调用时对原函数的操做 // 下面是伪代码 // function foo(){ // xx.call({'name':'jason'}) // } // 1.给xx(原函数)指定this 2.调用xx(原函数) // 必定要注意这两步是在新函数被调用时才发生,不调用不发生 // 你也能够总结为一句话,给原函数 call/apply 了一下
function list() { // 原函数【目标函数】 return Array.prototype.slice.call(arguments); } let listTest = list(1, 2, 3); // [1, 2, 3] // 新函数【绑定函数】 let leadingThirtysevenList = list.bind(undefined, 37); let list1 = leadingThirtysevenList(); // [37] let list2 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
思考过程
// 实现bind其实就是实现bind的特色 // 1.bind的第一个参数是this // 2.bind能够return一个新函数,这个新函数能够调用原函数而且能够指定其this,还能够接受参数 // 3.bind返回的新函数传递的参数要在bind传递的参数的后面
代码
Function.prototype._bind = function () { // 声明bind接受的参数【除去this】为bindArgs // 由于第一个参数是this,须要去掉 let bindArgs = Array.prototype.slice.call(arguments, 1) let bindThis = arguments[1] // 声明原函数【目标函数】为targetObj let targetObj = this return function () { // return出来的的函数接受的参数为newArgs // 要在return出来的新函数里把bindArgs和newArgs合并,使用数组的concat方法 let newArgs = Array.prototype.slice.call(arguments) return targetObj.apply(bindThis, bindArgs.concat(newArgs)) } }
你在控制台输入console.log(1)为何一个是1,一个是undefined?
1是执行console.log()方法的输出值,undefined是这个方法的返回值 因此,你要知道全部的函数都有返回值,必定要去关注一下函数的返回值
xxx.call()/xxx.apply() 的返回值是由xxx自己的返回值决定的 xxx.bind() 的返回值是一个函数