函数的四种调用模式:
1.函数模式
2.方法模式
3.构造器模式
4.上下文模式
先来说说函数模式和方法模式以及构造器模式:
函数调用模式:
定义一个函数,如果单独的将其调用,不将其与任何东西关联就是函数调用模式
function F(){}
F();
方法模式
定义一个函数,如果将函数赋值给一个对象的成员,那么利用
对象来调用,那么就是方法模式
function F(){}
var o = {}
o.f = F; //o['f'] = F
//o[0] = F o[0]();
o.f();//绑定在属性里面 方法模式
F();//自己调用自己 方法模式
构造器模式
定义一个函数,使用new来调用搬书就是构造器模式
function F(){}
new F();//构造器模式
F();//函数模式
o.F();//方法模式
这三种调用模式的区别:
都和this有关
1.函数模式this就是全局对象,(window);
2.方法模式this就是当前调用方法的对象.例如
Function.prototype.inherit = function(){
this
};
function f(){}
f.inherit();//如果用f调用,this就是f
Object.inherit();//如果用Object调用,this就是Obj
3.构造器模式
this就是new出来的新对象
构造函数模式有2点不同
1.this
2.return
在构造函数中如果没有return 默认就是返回当前对象
即this
如果return 后面是基本数据类型(数值,字符串,布尔)
忽略,和没写一样;
如果return 后面是有效的引用类型,无论构造函数中写什么内容,都返回return后面的对象
上下文调用模式
上下文其实就是一种环境,一块区域
‘在函数调用模式中函数模式都是固定的,在上下文调用模式中,this由上下文决定
function foo(){
console.log(this);
}
foo();//函数模式 window
var o = {fn:foo,name:'jim'};
o.fn();//方法模式 Object
new foo();//构造器模式 foo
上下文模式表示可以在调用的时候指定this的值是多少
有两种调用方法
功能一样,参数不同
1.函数名.apply(...);
2.函数名.call(...);
上下文模式由于可以指定this,可以模仿的调用有2种
1.方法模式
2.函数模式
不过使一些手段也可以模仿构造器模式
模拟函数调用
foo.apply();
//什么参数都不写,代表函数调用模式
//不传参,this就是window
模拟方法调用模式
var o = {name:'jack'};
foo.apply(o);//传参 this就是这个对象foo
//传什么就相当于用什么对象调用该方法
//借用方法调用,本身没有这个方法,但是能根据这个方法的特性去完成这个事情就叫借用方法调用
什么是上下文调用?
就是让函数既可以当函数来调用也可以当对象来调用
apply的参数:
第一个参数表示指定的this对象,第二个参数要求是数组表示函数的参数
昨天因为有点累了,写的有点仓促,call方法现在补上
其实和apply方法功能一样,只是后面的参数不同,会用apply就会call
举例:
使用apply
var o = {length:0};
[].push.apply( o,[ 1 ] );//这里的[]相当于Array.prototype
[].push.apply( o,[ 2 ] );
使用call
var objArr ={length:0};
[].push.call( objArr,1 );
[].push.call( objArr,2 );
调试
从图中可以看到,他们的值都是一样的apply方法虽然好用但是写起来麻烦,apply方法第二个参数加的必须是数组,每次都得加[]
不论是调用join,slice,splice…都得加上[],所以有了一个call方法
,call方法的功能和apply方法一模一样唯一不同的是调用参数的时候不需要使用数组[].
上面只加了一个参数,那么加多个参数呢
加多个参数
var arr1 = [];
arr1.push(1,2,3,4,5);
var o1 = {length:0};
var o2 = {length:0};
[].push.apply( o1,[1,2,3,4,5]);
[].push.call( o2,1,2,3,4,5);
除了 o1和o2不同之外 其实后面的参数相当于arr1.push(1,2,3,4,5);里的参数
apply和call的最大区别在于:在实际开发的用apply可以作为一个整体放数据而call不能当做一个整体
举例
var list = document.getElementsTagName('div');//得到的是一个伪数组
如果需要得到一个真数组,可以这么做
var new Arr = [].slice(0);//什么都不传或者传个0,就把第0项位置开始到最后一个返回,得到一个新数组
既然list是一个伪数组就不能直接通过slice来完成需要直放到一个数组里
所以用push方法,将数据添加到数组里
[].push(1,2,3,4)
[].push.call( [],list );
如果用这种方法不能直接把list放到这里面
这样是把list这个伪数组当成一个元素放到这里面数组里了
而我们处理这个参数的时候应该把它当整体,做一个数组,所以不推荐用call,所以为了节约我们可以用[].push.apply( [],list );