进阶学习 在JavaScript中借用方法
沉沙 2018-07-23 来源 : 阅读 1052 评论 0

摘要:本篇JavaScript教程探讨了在JavaScript中借用方法,希望阅读本篇文章以后大家有所收获,帮助大家对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 借用方法才更加简便?估计这样的话题会越来越常见。

 

本文由职坐标整理发布,更多相关内容,请关注职坐标WEB前端JavaScript频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程