align="center">#405f74a5752f08de687984beb7ebca0b#
函数原型链中的 apply,call 和 bind 方法是 JavaScript 中相当重要的概念,与 this 关键字密切相关,相当一部分人对它们的理解还是比较浅显,所谓js基础扎实,绕不开这些基础常用的API,这次让我们来彻底掌握它们吧!
目录call/apply/bind的核心理念:借用方法
call和apply的应用场景
bind的应用场景
中高级面试题:手写call/apply、bind
call,apply,bind的基本介绍 语法: fun.call(thisArg, param1, param2, ...) fun.apply(thisArg, [param1,param2,...]) fun.bind(thisArg, param1, param2, ...) 返回值:call/apply:fun执行的结果
bind:返回fun的拷贝,并拥有指定的this值和初始参数
thisArg(可选):
fun的this指向thisArg对象
非严格模式下:thisArg指定为null,undefined,fun中的this指向window对象.
严格模式下:fun的this为undefined
值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象,如 String、Number、Boolean
param1,param2(可选): 传给fun的参数。
如果param不传或为 null/undefined,则表示不需要传入任何参数.
apply第二个参数为数组,数组内的值为传给fun的参数。
调用call/apply/bind的必须是个函数call、apply和bind是挂在Function对象上的三个方法,只有函数才有这些方法。
只要是函数就可以,比如: Object.prototype.toString就是个函数,我们经常看到这样的用法:Object.prototype.toString.call(data)
作用:改变函数执行时的this指向,目前所有关于它们的运用,都是基于这一点来进行的。
如何不弄混call和aaply弄混这两个API的不在少数,不要小看这个问题,记住下面的这个方法就好了。
apply是以a开头,它传给fun的参数是Array,也是以a开头的。
区别: call与apply的唯一区别传给fun的参数写法不同:
apply是第2个参数,这个参数是一个数组:传给fun参数都写在数组中。
call从第2~n的参数都是传给fun的。
call/apply与bind的区别执行:
call/apply改变了函数的this上下文后马上执行该函数
bind则是返回改变了上下文后的函数,不执行该函数
返回值:
call/apply 返回fun的执行结果
bind返回fun的拷贝,并指定了fun的this指向,保存了fun的参数。
返回值这段在下方bind应用中有详细的示例解析。
call/apply/bind的核心理念:借用方法看到一个非常棒的例子:
生活中:
平时没时间做饭的我,周末想给孩子炖个腌笃鲜尝尝。但是没有适合的锅,而我又不想出去买。所以就问邻居借了一个锅来用,这样既达到了目的,又节省了开支,一举两得。
程序中:
A对象有个方法,B对象因为某种原因也需要用到同样的方法,那么这时候我们是单独为 B 对象扩展一个方法呢,还是借用一下 A 对象的方法呢?
当然是借用 A 对象的方法啦,既达到了目的,又节省了内存。
这就是call/apply/bind的核心理念:借用方法。
借助已实现的方法,改变方法中数据的this指向,减少重复代码,节省内存。
call和apply的应用场景:这些应用场景,多加体会就可以发现它们的理念都是:借用方法
判断数据类型:
Object.prototype.toString用来判断类型再合适不过,借用它我们几乎可以判断所有类型的数据:
function isType(data, type) { const typeObj = { '[object String]': 'string', '[object Number]': 'number', '[object Boolean]': 'boolean', '[object Null]': 'null', '[object Undefined]': 'undefined', '[object Object]': 'object', '[object Array]': 'array', '[object Function]': 'function', '[object Date]': 'date', // Object.prototype.toString.call(new Date()) '[object RegExp]': 'regExp', '[object Map]': 'map', '[object Set]': 'set', '[object HTMLDivElement]': 'dom', // document.querySelector('#app') '[object WeakMap]': 'weakMap', '[object Window]': 'window', // Object.prototype.toString.call(window) '[object Error]': 'error', // new Error('1') '[object Arguments]': 'arguments', } let name = Object.prototype.toString.call(data) // 借用Object.prototype.toString()获取数据类型 let typeName = typeObj[name] || '未知类型' // 匹配数据类型 return typeName === type // 判断该数据类型是否为传入的类型 } console.log( isType({}, 'object'), // true isType([], 'array'), // true isType(new Date(), 'object'), // false isType(new Date(), 'date'), // true )类数组借用数组的方法:
类数组因为不是真正的数组所有没有数组类型上自带的种种方法,所以我们需要去借用数组的方法。