Function对象(apply、call、bind)

原创文章,转摘请注明出处:苏福:http://www.cnblogs.com/susufufu/p/5850180.html

本文参考MDN做的详细整理,方便大家参考[MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript)

Function 构造器会创建一个新的 Function 对象。 在 JavaScript 中每个函数都是一个Function对象。

构造器

new Function ([arg1[, arg2[, ...argN]],] functionBody)

  • arg1, arg2, ... arg被函数使用的参数的名称必须是有效的JavaScript标识符的字符串
  • functionBody 一个含有包括函数定义的JavaScript语句的字符串。
  • 以调用函数的方式调用Function的构造函数 (不是用new关键字) 跟以构造函数来调用是一样的.

例:var adder = new Function("a", "b", "return a + b"); // 创建了一个能返回两个参数和的函数

adder(2, 6); //  8

使用Function构造器生成的Function对象是在函数创建时解析的。这比你使用函数声明或者函数表达式(function)并在你的代码中调用更为低效,因为使用后者创建的函数是跟其他代码一起解析的。

所有被传递到构造函数中的参数,都将被视为将被创建的函数的参数,并且是相同的标示符名称和传递顺序。

使用Function构造器生成的函数,并不会在创建它们的上下文中创建闭包;它们一般在全局作用域中被创建。当运行这些函数的时候,它们只能访问自己的本地变量和全局变量,不能访问Function构造器被调用生成的上下文的作用域。这和使用带有函数表达式代码的 eval 不同。

属性:

Function.length

length 是函数对象的一个属性值,指明该函数期望多少个参数,即形参的个数。数量不包括剩余参数。相比之下,  arguments.length 是函数被调用时实际传参的个数。

  • Function 构造器本身也是个Function。他的 length 属性值为 1 。该属性 Writable: false, Enumerable: false, Configurable: true.
  • Function  原型对象的 length 属性值为 0 。

方法

Function.prototype.call(thisArg[, arg1[, arg2[, ...]]])

在一个对象thisArg的上下文中应用另一个对象的方法;参数能够以列表形式传入,即在使用一个指定的this值(thisArg)和若干个指定的参数值的前提下调用某个函数或方法。

  • 需要注意的是,指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于非严格模式下,则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。

call方法的应用:

  • 使用call方法调用函数并且指定上下文的'this'
function greet() {
  var reply = [this.person, 'Is An Awesome', this.role].join(' ');
  console.log(reply);
}
var a = {
  person: 'Douglas Crockford', role: 'Javascript Developer'
};
greet.call(a); // Douglas Crockford Is An Awesome Javascript Developer
  • 使用call方法调用父构造函数:在一个子构造函数中,你可以通过调用父构造函数的 call 方法来实现继承
function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}
  • 使用call方法调用匿名闭包函数,以达到绑定this和传参数的目的
for(var i =0;i<10;i++){
  setTimeout(function(){
    console.log(i);
  }.call(null,i),0)
}
//可以顺利输出0~9,如果不用call,则i的最终值,输出10个10

Function.prototype.apply(thisArg[, argsArray])

在一个对象的上下文中应用另一个对象的方法;参数能够以数组形式传入。

  • thisArg 在函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。
  • argsArray 一个数组或者类数组对象(ES5新增,Chrome 14 以及 Internet Explorer 9 仍然不接受类数组对象。如果传入类数组对象,它们会抛出异常。),其中的数组元素将作为单独的参数传给函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。浏览器兼容性请参阅本文底部内容。
  • 使用 apply和call, 你可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法。
  • 可以使用 arguments 对象作为 argsArray 参数。 arguments 是一个函数的局部变量。 它可以被用作被调用对象的所有未指定的参数。 这样,你在使用apply函数的时候就不需要知道被调用对象的所有参数。 你可以使用arguments来把所有的参数传递给被调用对象。

使用apply和内置函数

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

var numbers = [5, 6, 2, 3, 7];
var max = Math.max.apply(null, numbers);
var min = Math.min.apply(null, numbers);
  • 当你对一个方法传入非常多的参数 (比如超过1W多个参数) 时, 就非常有可能会导致越界问题, 这个临界值是根据不同的 JavaScript 引擎而定的 (JavaScript 核心中已经做了硬编码 参数个数限制在65536),因为这个限制(实际上也是任何用到超大栈空间的行为的自然表现)是未指定的. 有些引擎会抛出异常.  更糟糕的是其他引擎会直接限制传入到方法的参数个数,导致参数丢失.
  • 如果你的参数数组可能非常大, 那么推荐使用下面这种策略来处理: 将参数数组切块后循环传入目标方法:
function minOfArray(arr) {
  var min = Infinity;
  var QUANTUM = 32768;
  for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
    var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len)));
    min = Math.min(submin, min);
  }
  return min;
}
var min = minOfArray([5, 6, 2, 3, 7]);

Function.prototype.bind(thisArg[, arg1[, arg2[, ...]]])

bind()方法会创建一个新函数(新函数与被调函数具有相同的函数体)称为绑定函数。

  • 当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind()方法的第二个以及以后的参数作为绑定函数的预设参数,加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数.
  • 一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
function Point(x, y) {
  this.x = x;
  this.y = y;
}
Point.prototype.add = function() {
  return this.x + this.y;
};
var p = new Point(1, 2);
console.log(p); //Point { x: 1, y: 2 }
var YAxisPoint = Point.bind({}, 5);
var x = new YAxisPoint(6);
console.log(x); //Point { x: 5, y: 6 }
console.log(x.add()); //11

bind用法:

bind() 最简单的用法是为原函数创建一个绑定函数,绑定到指定的对象上,使这个函数不论怎么调用都有同样的 this 值

this.x = 9;
var module = {
  x: 81,
  getX: function() { return this.x; }
};
module.getX(); // 返回 81
var retrieveX = module.getX;
retrieveX(); // 返回 9, 在这种情况下,"this"指向全部作用域
// 创建一个新函数,将"this"绑定到module对象
// 新手可能会被全局的x变量和module里的属性x所迷惑
var boundGetX = retrieveX.bind(module);
boundGetX(); // 返回 81

bind()的另一个最简单的用法是使一个函数拥有预设的初始参数

function list() {
  return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
var leadingThirtysevenList = list.bind(undefined, 37);
var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
function foo(x,y){
  return y ? x+y : foo.bind(void 0,x)
}
console.log(foo(1,4)); //3
console.log(foo(1)(4)); //3

配合 setTimeout,在默认情况下,使用 window.setTimeout() 时,this 关键字会指向 window (或全局)对象。当使用类的方法时,需要 this 引用类的实例,你可能需要显式地把 this 绑定到回调函数以便继续使用实例。

function LateBloomer() {
  this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
LateBloomer.prototype.bloom = function() {
  window.setTimeout(this.declare.bind(this), 1000);
};
LateBloomer.prototype.declare = function() {
  console.log('I am a beautiful flower with ' +
  this.petalCount + ' petals!');
};
var flower = new LateBloomer();
flower.bloom(); // 一秒钟后, 调用\'declare\'方法

Function.prototype.toString()

获取函数的实现源码的字符串。覆盖了 Object.prototype.toString 方法。

 
 
 
 

原生JS:Function对象(apply、call、bind)详解的更多相关文章

  1. JS DOM对象控制HTML元素详解

    JS DOM对象控制HTML元素详解 方法: getElementsByName()  获取name getElementsByTagName()  获取元素 getAttribute()  获取元素 ...

  2. call,apply,bind详解

    为什么要改变this指向? 我们知道bind,call,apply的作用都是用来改变this指向的,那为什么要改变this指向呢?请看下面的例子: var name="lucy"; ...

  3. 原生JS获取元素宽高实践详解

    开篇的话 任何不是亲身实践中求得的知识,都不是属于你的.任何求得的知识不去时常温习运用,也不是属于你的. 记录由来 在做个上拉广告功能中遇到了一个"理所当然"觉得对的用法,慢慢才排 ...

  4. call,apply和bind详解

    一.call和apply call和apply其实是同一个东西,区别只有参数不同,call是apply的语法糖,所以就放在一起说了,这两个方法都是定义在函数对象的原型上的(Function.proto ...

  5. javascript中call、apply、bind详解

    1.apply和call的区别在哪里 2.什么情况下用apply,什么情况下用call 3.apply的其他巧妙用法(一般在什么情况下可以使用apply) 我首先从网上查到关于apply和call的定 ...

  6. js对象浅拷贝和深拷贝详解

    js对象浅拷贝和深拷贝详解 作者:i10630226 字体:[增加 减小] 类型:转载 时间:2016-09-05我要评论 这篇文章主要为大家详细介绍了JavaScript对象的浅拷贝和深拷贝代码,具 ...

  7. react第五单元(事件系统-原生事件-react中的合成事件-详解事件的冒泡和捕获机制)

    第五单元(事件系统-原生事件-react中的合成事件-详解事件的冒泡和捕获机制) 课程目标 深入理解和掌握事件的冒泡及捕获机制 理解react中的合成事件的本质 在react组件中合理的使用原生事件 ...

  8. JS中的函数节流throttle详解和优化

    JS中的函数节流throttle详解和优化在前端开发中,有时会为页面绑定resize事件,或者为一个页面元素绑定拖拽事件(mousemove),这种事件有一个特点,在一个正常的操作中,有可能在一个短的 ...

  9. js replace 与replaceall实例用法详解

    这篇文章介绍了js replace 与replaceall实例用法详解,有需要的朋友可以参考一下stringObj.replace(rgExp, replaceText) 参数 stringObj 必 ...

随机推荐

  1. 日志log2

    public class LoggerHelper2 { private static ConcurrentQueue<string> CqMsg = null; private stat ...

  2. intellij IDEA 出现“Usage of API documented as @since 1.6+”的解决办法

    问题 在导入java.io.console的时候出现"Usage of API documented as @since 1.6+"

  3. C#设计模式系列:职责链模式(Chain of Responsibility)

    1.职责链模式简介 1.1>.定义 职责链模式是一种行为模式,为解除请求的发送者和接收者之间的耦合,而使多个对象都有机会处理这个请求.将这些对象连接成一条链,并沿着这条链传递该请求,直到有一个对 ...

  4. OpenCASCADE Rational Bezier Curves

    OpenCASCADE Rational Bezier Curves eryar@163.com Abstract. Although polynomials offer many advantage ...

  5. c++ stringstream(老好用了)

    前言: 以前没有接触过stringstream这个类的时候,常用的字符串和数字转换函数就是sscanf和sprintf函数.开始的时候就觉得这两个函数应经很叼了,但是毕竟是属于c的.c++中引入了流的 ...

  6. Hibernate的数据查找,添加!

    1.首先看一下测试数据库的物理模型 2.测试所需要的Hibernate的jar包 3.数据库的sql /*=============================================== ...

  7. C#互斥体——Mutex

    Mutex对象是一个同步基元,可以用来做线程间的同步. 若多个线程需要共享一个资源,可以在这些线程中使用Mutex同步基元.当某一个线程占用Mutex对象时,其他也需要占用Mutex的线程将处于挂起状 ...

  8. 【经验之谈】Windows环境下配置WordPress

    前言 wordpress全球著名的开放博客平台,拥有成千上万个各式插件和不计其数的主题模板样式,使用php和mysql搭建,下面说下载windows环境下配置wordpress,经验之谈. 安装 关于 ...

  9. C# 提取Word文档中的图片

    C# 提取Word文档中的图片 图片和文字是word文档中两种最常见的对象,在微软word中,如果我们想要提取出一个文档内的图片,只需要右击图片选择另存为然后命名保存就可以了,今天这篇文章主要是实现使 ...

  10. 《selenium2 Java 自动化测试实战(第二版)》 更新2016.5.3

    java 版来了!! 本文档在<selenium2 Python 自动化测试实战>的基础上,将代码与实例替换为java ,当然,部分章节有变更.这主要更语言本身的特点有关.集合和java下 ...