来源
继承自Function.prototype中的,所以这三个方法都可以在对象,数组,函数中使用。
1 | console.log(Function.prototype.hasOwnProperty('call')) |
1 | function Person(name) { |
上面看起来三个函数的作用差不多,干的事几乎是一样的,那为什么要存在3个家伙呢,留一个不就可以。所以其实他们干的事从本质上讲都是一样的动态的改变this上下文,但是多少还是有一些差别的..
call()
调用一个对象的一个方法,以另一个对象替换当前对象。
1 | fun.call(thisArg[, arg1[, arg2[, ...]]]) |
Object.prototype.toString.call([]),就是一个Array对象借用了Object对象上的方法。
thisArg
函数运行时指定的this值,可能的值为:
- 不传,或者传null,undefined, this指向window对象
- 传递另一个函数的函数名fun2,this指向函数fun2的引用
- 值为原始值(数字,字符串,布尔值),this会指向该原始值的自动包装对象,如 String、Number、Boolean
- 传递一个对象,函数中的this指向这个对象
案例
1 | function a() { |
使用call方法调用匿名函数并且指定上下文的this
1 | function greet() { |
使用call方法调用匿名函数
1 | var animals = [ |
使用call方法调用函数传参数
1 | var a = { |
arguments转成数组
1 | function list() { |
为什么能实现这样的功能将arguments转成数组?(arguments
对象借用了Array
对象上的方法。)
首先call了之后,this指向了所传进去的arguments。我们可以假设slice方法的内部实现是这样子的:创建一个新数组,然后for循环遍历this,将this[i]一个个地赋值给新数组,最后返回该新数组。因此也就可以理解能实现这样的功能了。
将伪数组转化为数组
1 | var fakeArr = { |
判断变量类型
1 | function isArray(obj) { |
apply()
应用某一对象的一个方法,用另一个对象替换当前对象。
语法与 call() 方法的语法几乎完全相同,唯一的区别在于,apply的第二个参数必须是一个包含多个参数的数组(或类数组对象)。
1 | fun.apply(thisArg[, argsArray]) |
注意: 需要注意:Chrome 14 以及 Internet Explorer 9 仍然不接受类数组对象。如果传入类数组对象,它们会抛出异常。
argsArray
一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。
1 | function jsy(x, y, z) { |
案例
使用apply来链接构造器的例子
1 | Function.prototype.construct = function(aArgs) { |
内置函数调用
数组拼接
1 | var array1 = [1 , 2 , 3, 5]; |
最大或者最小值
1 | /* 使用 Math.min/Math.max 在 apply 中应用 */ |
1 | //通常情况我们会这样来找到数字的最大或者最小值 |
参数数组切块后循环传入
找到数字的最小值
1 | function minOfArray(arr) { |
bind() +ES5
函数会创建一个新函数(称为绑定函数),在ECMAScript5中扩展了叫bind的方法(IE6,7,8不支持),应用某一对象的一个方法,用另一个对象替换当前对象。
1 | fun.bind(thisArg[, arg1[, arg2[, ...]]]); |
- bind是ES5新增的一个方法
- 传参和call或apply类似
- 不会执行对应的函数,call或apply会自动执行对应的函数
- 返回对函数的引用
案例
保存this变量
1 | var foo = { |
EventClick
1 | /** |
call
页面会直接输出 JSLite.io p1 p2
1 | var obj = {name:'JSLite.io'}; |
bind()方法会创建一个新函数,称为绑定函数。 bind是ES5新增的一个方法,不会执行对应的函数(call或apply会自动执行对应的函数),而是返回对绑定函数的引用。 当调用这个绑定函数时,thisArg参数作为 this,第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。 简单地说,bind会产生一个新的函数,这个函数可以有预设的参数。
1 | function list() { |
原型扩展
1 | function test() { |
兼容处理
1 | if (!Function.prototype.bind) { |
区别
- call的arg传参需一个一个传,apply则直接传一个数组。
- call和apply直接执行函数,而bind需要再一次调用。
this
1 | var name = 'windowsName'; |
1 | var name = 'windowsName'; |
1 | var name = 'windowsName'; |
1 | var name = 'windowsName'; |
1 | var name = 'windowsName'; |
1 | var name = 'windowsName'; |
改变this指向
- 使用 ES6 的箭头函数
- 在函数内部使用 _this = this
- 使用 apply、call、bind
- new 实例化一个对象
1 | var name = 'windowsName'; |
在不使用箭头函数的情况下,是会报错的,因为最后调用 setTimeout 的对象是 window,但是在 window 中并没有 func1 函数。
箭头函数
1 | var name = 'windowsName'; |
函数内部使用
1 | var name = 'windowsName'; |
使用 apply、call、bind
1 | var name = 'windowsName'; |
1 | var name = 'windowsName'; |
1 | var name = 'windowsName'; |
JS 中的函数调用
作为一个函数调用
1 | var name = 'windowsName'; |
函数作为方法调用
1 | var name = 'windowsName'; |
使用构造函数调用函数
1 | function myFunction(arg1, arg2) { |
伪代码表示:
1 | var a = new myFunction('Li', 'Cherry'); |
作为函数方法调用函数(call、apply)
1 | var name = 'windowsName'; |
function
属性
- length:形参的个数;
- name:函数名;
- prototype:类的原型,在原型上定义的方法都是当前这个类的实例的公有方法;
- __proto__:把函数当做一个普通对象,指向Function这个类的原型
拓展
-回味JS基础:call apply 与 bind
-JS 中的 call、apply、bind 方法详解
-JS 中 call、apply、bind 那些事
-this、apply、call、bind
-JavaScript 中的 call、apply、bind 深入理解