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 ...
随机推荐
- 每天一个java基础知识--static
内存总体一共分为了 4个部分(stack segment.heap segment.code segment.data segment) 当我们在程序中,申明一个局部变量的时候,此变量就存放在了 st ...
- ligerui+json_001_实现表格(grid)的后台数据显示、分页
代码下载地址: http://download.csdn.net/detail/poiuy1991719/8556841 效果: 需要导入的包: 01:编写界面:index.jsp <%@ pa ...
- paper 43 :ENDNOTE下载及使用方法简介
转载来源:http://blog.sciencenet.cn/blog-484734-367968.html 软件下载来源: EndNote v9.0 Final 正式版:http://www.ttd ...
- linux进程自动关闭与dmesg的使用
一些应用程序,后台服务被关掉.例如内存不足等,可能是操作系统关掉的.这些日志记录在dmesg中. 存储目录:/var/log/dmesg dmesg -T 可以将时间戳转化为可以识别的时间. | he ...
- backend flow
在PD之后,netlist中会多出很多DCAP元件(去耦电容,减少IR-Drop)或者filter cell(保证芯片均匀度要求) 还有一些antenna cell也就是一些diode用来泻流,防止天 ...
- 如何设置DB2I(SPUFI)来正常工作
首先确定你现在所使用的登录proc,确保有权限可以在对应的PDS内新建member,可以在s.st里面找userid对应的job,然后去serach using,基本可以找到对应的dataset 用t ...
- hadoop自带例子wordcount的具体运行步骤
1.在hadoop所在目录“usr/local”下创建一个文件夹input root@ubuntu:/usr/local# mkdir input 2.在文件夹input中创建两个文本文件file1. ...
- .container_fluid 与 .container 的区别
.container 会在左右两侧留白边,而且是自动的,不用设置. .container{ padding-right:15px; padding-left:15px; margin-right:au ...
- 关于UIView(转)
曾经有人这么说过,在iphone里你看到的,摸到的,都是UIView,所以UIView在iphone开发里具有非常重要的作用.那么UIView我们到底知道多少呢.请看看下面的问题, 如果这些你都知道, ...
- web跨页弹窗选值
最近在项目中看到这样一种效果——点击当前网页文本框,然后弹出一个缩小的网页,并在网页里选择或填写数据,然后又返回当前网页,小网页关闭.感觉非常不错,其实在以前网上也看见过,只是当时没有留心.今天抽时间 ...