js Function
一、 arguments
arguments
是一个类数组对象。代表传给一个function的参数列表。arguments
对象是函数内部的本地变量;你可以在函数内部通过使用 arguments
对象来获取函数的所有参数。
这个对象为传递给函数的每个参数建立一个条目,条目的索引号从 0 开始。例如,如果一个函数有三个参数,你可以通过以下方式获取参数:
arguments[0] arguments[1] arguments[2]
arguments
对象并不是一个真正的Array
。它类似于数组,但没有数组所特有的属性和方法,除了 length。例如,它没有 pop 方法。不过可以将其转换成数组:
var args = Array.prototype.slice.call(arguments);
二、Function.prototype.apply()
apply()
方法在指定 this
值和参数(参数以数组或类数组对象的形式存在)的情况下调用某个函数。
语法:
fun.apply(thisArg[, argsArray])
使用apply
和内置函数
聪明的apply用法允许你在某些本来需要写成遍历数组变量的任务中使用内建的函数。在接下里的例子中我们会使用Math.max/Math.min来找出一个数组中的最大/最小值。
/* min/max number in an array */ var numbers = [5, 6, 2, 3, 7]; /* using Math.min/Math.max apply */ var max = Math.max.apply(null, numbers); /* This about equal to Math.max(numbers[0], ...) or Math.max(5, 6, ..) */ var min = Math.min.apply(null, numbers);
上面的代码中, 真正通过 apply
传到目标方法中的参数为 5, 6, 2, 3, 而不是完整的 numbers 数组.)
三、Function.prototype.call()
call()
方法在使用一个指定的this
值和若干个指定的参数值的前提下调用某个函数或方法.
语法:
fun.call(thisArg[, arg1[, arg2[, ...]]])
thisArg
在fun
函数运行时指定的this
值。
需要注意的是,指定的this
值并不一定是该函数执行时真正的this
值,如果这个函数处于非严格模式下,则指定为null
和undefined
的this值会自动指向
全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this
会指向该原始值的自动包装对象。arg1, arg2, ...
指定的参数列表。
通过 call 方法,
你可以在一个对象上借用另一个对象上的方法,比如Object.prototype.toString.call([]),
就是一个Array
对象借用了Object对象上的方法。
使用call
方法调用父构造函数
在一个子构造函数中,你可以通过调用父构造函数的 call
方法来实现继承,
类似于Java
中的写法。
function Product(name, price) { this.name = name; this.price = price; if (price < 0) { throw RangeError('Cannot create product ' + this.name + ' with a negative price'); } return this; } function Food(name, price) { Product.call(this, name, price); this.category = 'food'; } Food.prototype = Object.create(Product.prototype); Food.prototype.constructor = Food; // Reset the constructor from Product to Food function Toy(name, price) { Product.call(this, name, price); this.category = 'toy'; } Toy.prototype = Object.create(Product.prototype); Toy.prototype.constructor = Toy; // Reset the constructor from Product to Toy var cheese = new Food('feta', 5); var fun = new Toy('robot', 40);
使用call
方法调用匿名函数
这个匿名函数的主要目的是给每个数组元素对象添加一个print
方法,这个print
方法可以打印出各元素在数组中的正确索引号。当然,这里不是必须得让数组元素作为this
值传入那个匿名函数(普通参数就可以),目的是为了演示call
的用法。
var animals = [ {species: 'Lion', name: 'King'}, {species: 'Whale', name: 'Fail'} ]; for (var i = 0; i < animals.length; i++) { (function (i) { this.print = function () { console.log('#' + i + ' ' + this.species + ': ' + this.name); } this.print(); }).call(animals[i], i); }
四、Function.prototype.bind()
bind()方法会创建一个新函数,当这个新函数被调用时,它的this值是传递给bind()的第一个参数, 它的参数是bind()的其他参数和其原本的参数.
语法:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。当使用new
操作符调用绑定函数时,该参数无效。
arg1, arg2, ...
当绑定函数被调用时,这些参数加上绑定函数本身的参数会按照顺序作为原函数运行时的参数。
描述:
bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call
属性)。当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。一个绑定函数也能使用new
操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
示例:
创建绑定函数
bind() 最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的
this
值。
this.x = 9; var module = { x: 81, getX: function() { return this.x; } }; module.getX(); // 81 var retrieveX = module.getX; retrieveX(); // 9, because in this case, "this" refers to the global object // Create a new function with 'this' bound to module //New programmers (like myself) might confuse the global var getX with module's property getX var boundGetX = retrieveX.bind(module); boundGetX(); // 81
分离函数(Partial Functions)
bind()
的另一个最简单的用法是使一个函数拥有预设的初始参数。
function list() { return Array.prototype.slice.call(arguments); } var list1 = list(1, 2, 3); // [1, 2, 3] // Create a function with a preset leading argument var leadingThirtysevenList = list.bind(undefined, 37); var list2 = leadingThirtysevenList(); // [37] var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
配合 setTimeout
function LateBloomer() { this.petalCount = Math.ceil(Math.random() * 12) + 1; } // Declare bloom after a delay of 1 second 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'方法
Polyfill(兼容旧浏览器IE6~8)
if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () {}, fBound = function () { return fToBind.apply(this instanceof fNOP ? this : oThis || this, aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; }; }