百科狗-知识改变命运!
--

Function.prototype.apply() - JavaScript Function 对象

百变鹏仔1年前 (2023-11-21)阅读数 30#技术干货
文章标签数组

Function.prototype.apply()

apply()方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。

注意: call()方法的作用和 apply()方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组

语法

func.apply(thisArg, [argsArray])

参数

thisArg可选的。在func函数运行时使用的this值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为nullundefined时会自动替换为指向全局对象,原始值会被包装。argsArray可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给func函数。如果该参数的值为nullundefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。浏览器兼容性请参阅本文底部内容。

返回值

调用有指定this值和参数的函数的结果。

描述

在调用一个存在的函数时,你可以为其指定一个this对象。this指当前对象,也就是正在调用这个函数的对象。使用apply,你可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法。

applycall()非常相似,不同之处在于提供参数的方式。apply使用参数数组而不是一组参数列表。apply可以使用数组字面量(array literal),如fun.apply(this,['eat','bananas']),或数组对象,如fun.apply(this, new Array('eat','bananas'))

你也可以使用arguments对象作为argsArray参数。arguments是一个函数的局部变量。它可以被用作被调用对象的所有未指定的参数。这样,你在使用apply函数的时候就不需要知道被调用对象的所有参数。你可以使用arguments来把所有的参数传递给被调用对象。被调用对象接下来就负责处理这些参数。

从 ECMAScript 第5版开始,可以使用任何种类的类数组对象,就是说只要有一个length属性和(0..length-1)范围的整数属性。例如现在可以使用NodeList或一个自己定义的类似{'length': 2,'0':'eat','1':'bananas'}形式的对象。

需要注意:Chrome 14 以及 Internet Explorer 9 仍然不接受类数组对象。如果传入类数组对象,它们会抛出异常。

示例

apply将数组添加到另一个数组

我们可以使用push将元素追加到数组中。并且,因为push接受可变数量的参数,我们也可以一次推送多个元素。但是,如果我们传递一个数组来推送,它实际上会将该数组作为单个元素添加,而不是单独添加元素,因此我们最终得到一个数组内的数组。如果那不是我们想要的怎么办?在这种情况下,concat确实具有我们想要的行为,但它实际上并不附加到现有数组,而是创建并返回一个新数组。但是我们想要附加到我们现有的阵列......那么现在呢?写一个循环?当然不是吗?

apply来帮你!

var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]

使用apply和内置函数

聪明的apply用法允许你在某些本来需要写成遍历数组变量的任务中使用内建的函数。在接下里的例子中我们会使用Math.max/Math.min来找出一个数组中的最大/最小值。

/* 找出数组中最大/小的数字 */
var numbers = [5, 6, 2, 3, 7];

/* 应用(apply) Math.min/Math.max 内置函数完成 */
var max = Math.max.apply(null, numbers); /* 基本等同于 Math.max(numbers[0], ...) 或 Math.max(5, 6, ..) */
var min = Math.min.apply(null, numbers);

/* 代码对比: 用简单循环完成 */
max = -Infinity, min = +Infinity;

for (var i = 0; i  max)
    max = numbers[i];
  if (numbers[i] 

但是当心:如果用上面的方式调用apply,会有超出JavaScript引擎的参数长度限制的风险。当你对一个方法传入非常多的参数(比如一万个)时,就非常有可能会导致越界问题,这个临界值是根据不同的 JavaScript 引擎而定的(JavaScript 核心中已经做了硬编码参数个数限制在65536),因为这个限制(实际上也是任何用到超大栈空间的行为的自然表现)是未指定的.有些引擎会抛出异常。更糟糕的是其他引擎会直接限制传入到方法的参数个数,导致参数丢失。举个例子:如果某个引擎限制了方法参数最多为4个(实际真正的参数个数限制当然要高得多了,这里只是打个比方),上面的代码中,真正通过apply传到目标方法中的参数为5, 6, 2, 3而不是完整的数组。

如果你的参数数组可能非常大,那么推荐使用下面这种策略来处理:将参数数组切块后循环传入目标方法:

function minOfArray(arr) {
  var min = Infinity;
  var QUANTUM = 32768;

  for (var i = 0, len = arr.length; i 

使用apply来链接构造器

你可以使用apply来链接一个对象构造器,类似于Java。在接下来的例子中我们会创建一个全局Function对象的construct方法,来使你能够在构造器中使用一个类数组对象而非参数列表。

Function.prototype.construct = function (aArgs) {
  var oNew = Object.create(this.prototype);
  this.apply(oNew, aArgs);
  return oNew;
};

注意:上面使用的Object.create()方法相对来说比较新。另一种可选的方法,请考虑如下替代方法:

Function.prototype.apply() - JavaScript Function 对象

Using Object.__proto__:

Function.prototype.construct = function (aArgs) {
  var oNew = {};
  oNew.__proto__ = this.prototype;
  this.apply(oNew, aArgs);
  return oNew;
};

使用闭包:

Function.prototype.construct = function(aArgs) {
  var fConstructor = this, fNewConstr = function() {
    fConstructor.apply(this, aArgs);
  };
  fNewConstr.prototype = fConstructor.prototype;
  return new fNewConstr();
};

使用 Function 构造器:

Function.prototype.construct = function (aArgs) {
  var fNewConstr = new Function("");
  fNewConstr.prototype = this.prototype;
  var oNew = new fNewConstr();
  this.apply(oNew, aArgs);
  return oNew;
};

使用示例:

function MyConstructor (arguments) {
    for (var nProp = 0; nProp 注意:这个非native的Function.construct方法无法和一些native构造器(例如Date)一起使用。在这种情况下你必须使用Function.bind方法(例如,想象有如下一个数组要用在Date构造器中:[2012, 11, 4];这时你需要这样写:new(Function.prototype.bind.apply(Date,[null].concat([2012, 11, 4])))()–-无论如何这不是最好的实现方式并且也许不该用在任何生产环境中). 

鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com

免责声明:我们致力于保护作者版权,注重分享,当前被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!邮箱:344225443@qq.com)

图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

内容声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。部分内容参考包括:(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供参考使用,不准确地方联系删除处理!本站为非盈利性质站点,本着为中国教育事业出一份力,发布内容不收取任何费用也不接任何广告!)