apply: 方法在指定 this 值和参数(参数以数组或类数组对象的形式存在)的情况下调用某个函数。能劫持另外一个对象的方法,继承另外一个对象的属性。
- Function.apply(obj,args)
obj:在 fun 函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。
args:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给Function函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。
- //定义一个Person类
- function Person(name, sex){
- this.name = name;
- this.sex = sex;
- }
- //定义一个Engineer类
- function Engineer(name, sex, appearance){
- Person.apply(this, arguments);
- this.appearance = appearance;
- }
- //创建一个Engineer类
- var eng = new Engineer("staven", "男", "handsome");
- console.log(eng.name+"是一位"+eng.appearance+"的"+eng.sex+"士!"); //staven是一位handsome的男士!
可理解为当前的this代表的Engineer对象去借用Person类的属性与方法,这样自己也就拥有了这些属性与方法的使用权。
Function.apply(obj,args)方法能接收两个参数。obj:这个对象将代替Function类里this对象;args:这个是数组,它将作为参数传给Function(args-->arguments)。
- foo.call(this, arg1, arg2, arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3)
apply与call的异同
apply:
- Function.apply(obj, args)
call:
- Function.apply(obj, arg1, arg2, ……)
相同点:两个方法产生的作用是完全一样的。
不同点:从第二个参数起, call方法参数将依次传递给借用的方法作参数, 而apply直接将这些参数放到一个数组中再传递, 最后借用方法的参数列表是一样的.
apply使用场景:
使用apply来连接构造器
- Function.prototype.say = function(args){
- var that = this,
- newObj = function(){
- that.apply(this, args);
- }
- newObj.prototype = that.prototype;
- return new newObj();
- }
- function sayArgs(){
- for(var i=0; i<arguments.length; i++){
- this["arg"+i] = arguments[i];
- }
- }
- var argsArr = ["hello","staven","handsome man"];
- var p = sayArgs.say(argsArr);
- console.log(p.arg1); //staven
- Function.prototype.say = function(args){
- var newObj = Object.create(this.prototype);
- this.apply(newObj, args);
- return newObj;
- }
- function sayArgs(){
- for(var i=0; i<arguments.length; i++){
- this["arg"+i] = arguments[i];
- }
- }
- var argsArr = ["hello","staven","handsome man"];
- var p = sayArgs.say(argsArr);
- console.log(p.arg1);
apply参数逐个解析
调用apply方法的时候apply(obj,args),="" 第二个参数args是一个数组集合,仍然将会解析为一个一个的参数,这个就是apply的一个巧妙的用处。利用这个特性可以用于一些特殊的场景。
math.max()得到数组中最大的一项。
math.max()函数用于返回一个或多个数中最大的数。如果没有传入任何参数,则返回负的无穷大(-infinity);如果参数中存在为nan的值,则返回nan。
math.max()并不支持数组。传统方式获取数组中最大值:
- var arr = [4,5,32,9,231,2,56];
- function getMaxVal(arr){
- var arrLen = arr.length;
- for (var i=0,initVal=arr[0]; i<arrLen; i++) {
- initVal = Math.max(initVal, arr[i]);
- }
- return initVal;
- }
- console.log(getMaxVal(arr)); //231
使用apply,可有效简化操作步骤:
- var arr = [4,5,32,9,231,2,56];
- console.log(Math.max.apply(null, arr)); //231
Array.prototype.push可以实现两个数组合并
push()方法可向数组的末尾添加一个或多个元素,并返回新的长度。
- var arr1 = [1,2,3];
- var arr2 = [4,5,6];
- arr1.push(arr2)
- console.log(arr1); //[1, 2, 3, Array[3]]
concat()="" 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
- var arr1 = [1,2,3];
- var arr2 = [4,5,6];
- console.log(arr1.concat(arr2)); //[1, 2, 3, 4, 5, 6]
- console.log(arr1); //[1, 2, 3]
若想将arr1、arr2合并到arr1中,显然上面两个方法实现不了。但可以这样做。
- var arr1 = [1,2,3];
- var arr2 = [4,5,6];
- arr1 = arr1.concat(arr2);
- console.log(arr1); //[1, 2, 3, 4, 5, 6]
再来看看使用apply如何实现的:
- var arr1 = [1,2,3];
- var arr2 = [4,5,6];
- Array.prototype.push.apply(arr1, arr2);
- console.log(arr1); //[1, 2, 3, 4, 5, 6]
call的应用场景
使用call方法调用父构造函数
- //定义一个Person类
- function Person(name, sex){
- this.name = name;
- this.sex = sex;
- }
- //定义一个Engineer类
- function Engineer(name, sex, appearance){
- Person.call(this, name, sex);
- this.appearance = appearance;
- }
- Engineer.prototype = Object.create(Person.prototype);
- Engineer.prototype.constructor = Engineer;
- //创建一个Engineer类
- var eng = new Engineer("staven", "男", "handsome");
- console.log(eng.name+"是一位"+eng.appearance+"的"+eng.sex+"士!"); //staven是一位handsome的男士!
使用call方法调用匿名函数
- var person = [
- {name:"staven",appearance:"handsome",sex:"man"},
- {name:"赫连小妖",appearance:"spirited",sex:"man"}
- ];
- for (var i=0;i<person.length; i++) {
- (function(i){
- this.say = function(){
- console.log(this.name+"是个非常"+this.appearance+"的"+this.sex);
- }
- this.say();
- }).call(person[i],i);
- }
- //staven是个非常handsome的man
- //赫连小妖是个非常spirited的man
使用call方法调用匿名函数并且指定上下文的'this'
- function say(){
- var content = [this.name,"是个非常",this.appearance,"的"+this.sex].join("");
- console.log(content);
- }
- var person = {
- name:"staven",
- appearance:"handsome",
- sex:"man"
- }
- say.call(person); //staven是个非常handsome的man