JS中的call()和apply()方法和bind()
1、方法定义
call方法:
语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明:
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。
apply方法:
语法:apply([thisObj[,argArray]])
定义:应用某一对象的一个方法,用另一个对象替换当前对象。
说明:
如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。
2.bind() 是es5中的新方法,可以改变函数的上下文this指向:
(function () {
var dd = function () { };
dd.alert = function () {
console.log("sss")
};
dd.kk = function () {
var ff = function () {
this.alert(); this不加bind就会指向kk那个函数,现在通过bind从而指向了dd
}.bind(this)
ff();
}
dd.kk()
})()
在ie678里面不支持bind。可以自己拓展
if(!function(){}.bind()){
Function.prototype.bind = function (context) {
var self = this,
args = [].slice.call(arguments);
return function () {
return self.apply(context, args.slice(1))
} }
}
function add(a,b)
{
alert(a+b);
}
function sub(a,b)
{
alert(a-b);
} add.call(sub,,); //4
function Animal(){
this.name = "Animal";
this.showName = function(){
alert(this.name);
}
} function Cat(){
this.name = "Cat";
} var animal = new Animal();
var cat = new Cat(); //通过call或apply方法,将原本属于Animal对象的showName()方法交给对象cat来使用了。
//输入结果为"Cat"
animal.showName.call(cat,",");
//animal.showName.apply(cat,[]);
今天看到一个
JavaScript中借用方法的不错:
在JavaScript中,有时可以重用其它对象的函数或方法,而不一定非得是对象本身或原型上定义的。通过 call()、apply() 和 bind() 方法,我们可轻易地借用其它对象的方法,而无须继承这些对象。这是专业 JavaScript 开发者常用的手段。
前提
本文假设你已经掌握使用 call()、apply() 和 bind() 的相关知识和它们之间的区别。
原型方法
在 JavaScript 中,除了不可更改的原始数据类型,如 string、number 和 boolean,几乎所有的数据都是对象。Array 是一种适用于遍历和转换有序数列的对象,其原型上有 slice、join、push 和 pop 等好用的方法。
一个常用的例子是,当对象和数组都是列表类型的数据结构时,对象可以从数组“借用”方法。最常借用的方法是 Array.prototype.slice。
function myFunc() {
// error, arguments is an array like object, not a real array
arguments.sort();
// "borrow" the Array method slice from its prototype, which takes an array like object (key:value)
// and returns a real array
var args = Array.prototype.slice.call(arguments);
// args is now a real Array, so can use the sort() method from Array
args.sort();
}
myFunc('bananas', 'cherries', 'apples');
借用方法之所以可行,是因为 call 和 apply 方法允许在不同上下文中调用函数,这也是重用已有功能而不必继承其它对象的好方法。实际上,数组在原型中定义了很多常用方法,比如 join 和 filter 也是:
// takes a string "abc" and produces "a|b|c
Array.prototype.join.call('abc', '|');
// takes a string and removes all non vowels
Array.prototype.filter.call('abcdefghijk', function(val) {
return ['a', 'e', 'i', 'o', 'u'].indexOf(val) !== -1;
}).join('');
可以看出,不仅对象可以借用数组的方法,字符串也可以。但是因为泛型方法是在原型上定义的,每次想要借用方法时都必须使用 String.prototype 或 Array.prototype。这样写很啰嗦,很快就会令人生厌。更有效的方法是使用字面量来达到同样的目的。
使用字面量借用方法
字面量是一种遵循JavaScript规则的语法结构,MDN 这样解释:
在JavaScript中,使用字面量可以代表值。它们是固定值,不是变量,就是在脚本中按字面给出的。
字面量可以简写原型方法:
[].slice.call(arguments);
[].join.call('abc', '|');
''.toUpperCase.call(['lowercase', 'words', 'in', 'a', 'sentence']).split(',');
这样看上去没有那么冗长了,但是必须直接在 [] 和 "" 上操作以借用方法,仍然有点丑。可以利用变量保存对字面量和方法的引用,这样写起来更简便些:
var slice = [].slice;
slice.call(arguments);
var join = [].join;
join.call('abc', '|');
var toUpperCase = ''.toUpperCase;
toUpperCase.call(['lowercase', 'words', 'in', 'a', 'sentence']).split(',');
有了借用方法的引用,我们就可以轻松地使用 call() 调用它了,这样也可以重用代码。秉着减少冗余的原则,我们来看看可否借用方法却不用每次调用都要写 call() 或者 apply():
var slice = Function.prototype.call.bind(Array.prototype.slice);
slice(arguments);
var join = Function.prototype.call.bind(Array.prototype.join);
join('abc', '|');
var toUpperCase = Function.prototype.call.bind(String.prototype.toUpperCase);
toUpperCase(['lowercase', 'words', 'in', 'a', 'sentence']).split(',');
如你所见,现在可以使用 Function.prototype.call.bind 来静态绑定从不同原型“借来的”方法了。但是 var slice = Function.prototype.call.bind(Array.prototype.slice) 这句话实际是如何起作用的呢?
理解 Function.prototype.call.bind
Function.prototype.call.bind 乍一看有些复杂,但是理解它是如何起作用的会非常有益。
Function.prototype.call 是一种引用,可以“call”函数并将设置其“this”值以在函数中使用。
注意“bind”返回一个存有其“this”值的新函数。因此 .bind(Array.prototype.slice) 返回的新函数的“this”总是 Array.prototype.slice 函数。
综上所述,新函数会调用“call”函数,并且其“this”为“slice”函数。调用 slice() 就会指向之前限定的方法。
自定义对象的方法
继承很棒,但是开发者通常在想要重用一些对象或模块间的通用功能时才会使用。没必要仅为代码重用使用继承,因为在多数情况下简单的借用方法会很复杂。
之前我们只讨论了借用原生方法,但是借用任何方法都是可以的。比如下面的代码可以计算积分游戏的玩家分数:
var scoreCalculator = {
getSum: function(results) {
var score = 0;
for (var i = 0, len = results.length; i < len; i++) {
score = score + results[i];
}
return score;
},
getScore: function() {
return scoreCalculator.getSum(this.results) / this.handicap;
}
};
var player1 = {
results: [69, 50, 76],
handicap: 8
};
var player2 = {
results: [23, 4, 58],
handicap: 5
};
var score = Function.prototype.call.bind(scoreCalculator.getScore);
// Score: 24.375
console.log('Score: ' + score(player1));
// Score: 17
console.log('Score: ' + score(player2));
虽然上面的例子很生硬,但是可以看出,就像原生方法一样,用户定义的方法也可以轻松借用。
总结
Call、bind 和 apply 可以改变函数的调用方式,并且经常在借用函数时使用。多数开发者熟悉借用原生方法,但是较少借用自定义的方法。
近几年 JavaScript 的函数式编程发展不错,怎样使用 Function.prototype.call.bind 借用方法才更加简便?估计这样的话题会越来越常见。
JS中的call()和apply()方法和bind()的更多相关文章
- 彻底理解了call()方法,apply()方法和bind()方法
javascript中的每一个作用域中都有一个this对象,它代表的是调用函数的对象.在全局作用域中,this代表的是全局对象(在web浏览器中指的是window).如果包含this的函数是一个对象的 ...
- JS中Date对象getYear()方法和getFullYear()方法区别
释义 JavaScript getFullYear() 方法 getFullYear() 方法可返回一个表示年份的 4 位数字. getYear() 语法 dateObject.getFullYear ...
- js中的this和apply
this是js的一个关键字,随着函数使用场合不同,this的值会发生变化.但是总有一个原则,那就是this指的是调用函数的那个对象. 1.纯粹函数调用. function test() { this. ...
- C#中??和?分别是什么意思? 在ASP.NET开发中一些单词的标准缩写 C#SESSION丢失问题的解决办法 在C#中INTERFACE与ABSTRACT CLASS的区别 SQL命令语句小技巧 JQUERY判断CHECKBOX是否选中三种方法 JS中!=、==、!==、===的用法和区别 在对象比较中,对象相等和对象一致分别指的是什么?
C#中??和?分别是什么意思? 在C#中??和?分别是什么意思? 1. 可空类型修饰符(?):引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; ...
- js笔记——理解js中的call及apply
call及apply在js里经常碰得到,但一直感觉很陌生,不能熟练使用.怎样才能熟练应用呢? 为什么存在call和apply? 在javascript OOP中,我们经常会这样定义: function ...
- JS中的call、apply、bind方法
JS中的call.apply.bind方法 一.call()和apply()方法 1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[, [,.argN]]] ...
- 关于 js 中的 call 和 apply使用理解
关于 js 中的 call 和 apply使用理解 在学习新的东西时候,碰到以前看过而又不理解,或则记忆不深的地方不妨回头看看书里知识点,有助于加深理解.正所谓--温故而知新. 废话不多说,直接上代码 ...
- 快速理解js中的call,apply的作用
今天被人问到js中的call,apply的区别和用途,解释了一番后,想到之前在逼乎上看到一位小伙伴生动形象的解释 本身不难理解,看下MDN就知道了,但是不常用,遇到了,还要脑回路回转下.或者时间长了, ...
- JS中的call()和apply()方法(转)
转自:http://uule.iteye.com/blog/1158829 JS中的call()和apply()方法 博客分类: JS 1.方法定义 call方法: 语法:call([thisOb ...
随机推荐
- ShowMessage和MessageDlg消息对话框(VCL)
ShowMessage一个简单的消息提示: 例如:ShowMessage("xxxx"); MessageDlg(constAnsiString Msg, TMsgDlgType ...
- 01分数规划zoj2676(最优比例,最小割集+二分)
ZOJ Problem Set - 2676 Network Wars Time Limit: 5 Seconds Memory Limit: 32768 KB S ...
- 传递闭包(Floyd+bellman-Fold POJ1932)
传递闭包 在一个有向(无向)连通图中,如果节点i与k联通,k与j联通,则i和j联通,传递闭包就是把所有传递性的节点求出来,之后就知道了任意两个节点的连通性,只需枚举节点的联通情况即可,无需考虑最短路径 ...
- 禁用cookie后session是如何设置的
我们都知道当在session 会话有基于cookie和基于url两种传递SESSIONID的方法.为了实现客户端禁止cookie发送的情况也不影响客户登陆网站,可以设置 php.ini中 sessio ...
- hdu5354 Bipartite Graph
分治+并查集.假设要求[L,mid]的答案,那么很明显,如果一条边的两个端点都>mid的话或者一个端点>mid一个端点<L,说明询问[L,mid]这个区间中任何一点时候,这一条边都是 ...
- Cocos2d-x游戏开发之计时器
首先写一个计时器的头文件GameTimer.h: #ifndef _GAME_TIMER_H_ #define _GAME_TIMER_H_ #include "cocos2d.h" ...
- linux代码段,数据段,BSS段, 堆,栈(二)
//main.cpp int a = 0; 全局初始化区 char *p1; 全局未初始化区 main() { int b; 栈 char s[] = "abc"; 栈 char ...
- paper 19 :机器学习算法(简介)
本来看了一天的分类器方面的代码,乱乱的,索性再把最基础的概念拿过来,现总结一下机器学习的算法吧! 1.机器学习算法简述 按照不同的分类标准,可以把机器学习的算法做不同的分类. 1.1 从机器学习问题角 ...
- Scrum站立会议----11月4日
小组名称:nice! 组长:李权 成员:于淼 刘芳芳韩媛媛 宫丽君 时间:2016.11.4 12:00--12:30 地点:传媒西楼220室 代码地址:Https: https://git ...
- [python] No module named _sysconfigdata_nd
when setting python environment in Ubuntu13.04, i got this error: ImportError: No module named _sysc ...