热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JS中的call()和apply()方法和bind()

1、方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 定义:调用一个对象的一个方法,

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,
3,1); //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

            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 借用方法才更加简便?估计这样的话题会越来越常见。

 

转:https://www.cnblogs.com/chenjinxinlove/p/5578871.html




推荐阅读
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 用Vue实现的Demo商品管理效果图及实现代码
    本文介绍了一个使用Vue实现的Demo商品管理的效果图及实现代码。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 如何优化Webpack打包后的代码分割
    本文介绍了如何通过优化Webpack的代码分割来减小打包后的文件大小。主要包括拆分业务逻辑代码和引入第三方包的代码、配置Webpack插件、异步代码的处理、代码分割重命名、配置vendors和cacheGroups等方面的内容。通过合理配置和优化,可以有效减小打包后的文件大小,提高应用的加载速度。 ... [详细]
  • 本文详细解析了JavaScript中相称性推断的知识点,包括严厉相称和宽松相称的区别,以及范例转换的规则。针对不同类型的范例值,如差别范例值、统一类的原始范例值和统一类的复合范例值,都给出了具体的比较方法。对于宽松相称的情况,也解释了原始范例值和对象之间的比较规则。通过本文的学习,读者可以更好地理解JavaScript中相称性推断的概念和应用。 ... [详细]
  • 本文总结了Java中日期格式化的常用方法,并给出了示例代码。通过使用SimpleDateFormat类和jstl fmt标签库,可以实现日期的格式化和显示。在页面中添加相应的标签库引用后,可以使用不同的日期格式化样式来显示当前年份和月份。该文提供了详细的代码示例和说明。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • java drools5_Java Drools5.1 规则流基础【示例】(中)
    五、规则文件及规则流EduInfoRule.drl:packagemyrules;importsample.Employ;ruleBachelorruleflow-group ... [详细]
  • HashMap的扩容知识详解
    本文详细介绍了HashMap的扩容知识,包括扩容的概述、扩容条件以及1.7版本中的扩容方法。通过学习本文,读者可以全面了解HashMap的扩容机制,提升对HashMap的理解和应用能力。 ... [详细]
  • tcpdump 4.5.1 crash 深入分析
    tcpdump 4.5.1 crash 深入分析 ... [详细]
author-avatar
捕鱼达人2602929461
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有