javaStript中的 函数调用形式主要有四种

一、函数调用形式

第一种定义函数

     //1.函数调用形式
    function function_name (argument) {
        console.log("this is a function");
        console.log(this);//this is a window
    }
    function_name();
    //window.function_name();这种调用类似的吧

第二种匿名函数

    //使用函数的Lambda表达式定义函数,然后调用
    var function_name = function() {
        console.log("this is a function");
        console.log(this);//this is a window
    };
    function_name();

如上两种所示,当前的执行环境都是window,直接的去调用

二、对象方法调用形式

函数调用模式很简单,是最基本的调用方式。
但是同样的是函数,将其赋值给一个对象的成员以后,就不一样了.
将函数赋值给对象的成员后,那么这个就不在称为函数,而应该叫做方法.
其可以看做为当前对象的方法,如果当前对象是类(可以看作为静态方法,我的理解)

    var function_name = function(){
        console.log('this is a function');
        console.log(this);
        // this is a object (objectName)
        //this is changed by this context(根据执行的环境而改变)
        //果果直接调用就是window对象,复值给某个对象之后,就是当前对象
    }
    var objectName = {};//this is a object
    objectName.fn = function_name;
    objectName.fn();// this is a function

类似的情况,和上面的差不多

    //下面这种写法,相当于向创建一个空的对象,然后赋值一个方法
    //就是对象调用方法
    var function_name ={
        fn:function(){
            console.log('this is a function');
            console.log(this);//this is a object
        }
    }
    function_name.fn();

三、构造调用形式

同样是函数,在单纯的函数模式下,this 表示 window。
在对象方法模式下,this 指的是当前对象。
除了这两种情况,JavaScript 中函数还可以是构造器
函数作为构造器来使用的语法就是在函数调用前面加上一个 new 关键字。

    var Person = function(){
        this.name ="wangji";
        this.age=24;
        this.sayMyNameAndAge = function(){
            console.log(""+this.age+this.name);
        }
        console.log(this);//this is Person object
    }
    var person = new Person();
    person.sayMyNameAndAge();

这里的this指向对象本身
所有需要由对象使用的属性,必须使用 this 引导。
函数的 return 语句意义被改写,如果返回非对象,就返回this。

分析创建的过程
  • 首先定义了函数Person,当程序执行到这里时不会执行函数体,因此 JavaScript 的解释器并不知道这个函数的内容。
  • 接下来执行new关键字,创建对象,解释器开辟内存,得到对象的引用,将新对象的引用交给函数
  • 紧接着执行函数,将传过来的对象引用交给this。也就是说,在构造方法中,this 就是刚刚被 new 创建出来的对象。
  • 然后为 this 添加成员,也就是为对象添加成员。
  • 最后函数结束,返回 this,将 this 交给左边的变量。
    分析过构造函数的执行以后,可以得到,构造函数中的 this 就是当前对象。
构造器中的 return
  • 在构造函数中 return 的意义发生了变化。
  • 首先如果在构造函数中,如果返回的是一个对象,那么就保留原意。
  • 如果返回的是非对象比如数字、布尔和字符串。那么就返回this。
  • 如果没有 return 语句,那么也返回 this。
例子:返回新的对象
    var Channge = function() {
        this.name = "汪吉";
        this.age = 25;
        return {
            name:"王老吉",
            age:24
        };
    };
    //如果返回的是对象,那么就是新的对象啦,以前的没得关系啦!
    var wangji = new Channge();
    console.log(wangji.name);//王老吉
    console.log(wangji.age);//24
例子:返回其他或者不返回
    var Channge = function() {
        this.name = "汪吉";
        this.age = 25;
        return "wangji";//其他或者不返回
        // return 语句无效
    };
    //如果返回的是其他(或者不返回),那么就是当前对象啦
    //自己在chrome 控制台试试
    var wangji = new Channge();
    console.log(wangji.name);//汪吉
    console.log(wangji.age);//25

四、apply and call

除了上述三种调用模式以外,函数作为对象还有 apply 方法与 call 方法可以使用,这便是第四种调用模式。
因为函数本身就是对象拥有自己的方法。

例子1:XXX.apply(null) 无参数
var funcTest1 = function() {
    this.name = "wangji";
    alert(this);//当前为window
};
//XXX.aply("上下文",[参数数组]);
//这里传null代表为全局的window
funcTest1.apply(null);
alert(name);
例子2:传入新创建的对象
    var funcTest2 = function() {
        this.name = "wangji";
        alert(this);//当前上下文(object)
    };
    //XXX.aply("上下文",[参数数组]);
    //这里传null代表为全局的window
    //这里传入objectName对象,改变funcTest2的执行上下文
    //所以funcTest2中的上下文为当前objectName
    //所以objectName能够调用之前funcTest2拥有的对象的方法。
    var objectName = {};
    funcTest2.apply(objectName);
    alert(objectName.name);
apply 和call相同,只是call调用(上下文,参数…);

JQuery中刚刚开始的时候有很多的变量,代表相应的函数,就是如下这样调用的。

    var arr = [];
    var push = arr.push;
    //这里arryTest使用了arr中的push函数
    var arryTest = [];
    push.call(arryTest,[1,2,3,4,5]);
    console.log(arryTest);//1,2,3,4,5

五、为什么这么使用 ?存在call和apply的原因

在javascript OOP中,定义一个类.
主要的目的就是为了重用,修改了当前的执行环境而已。

function Cat(){

};
Cat.prototype ={
    food:"fish",
    say:function(){
        console.log("I Love food is :",this.food);
    }
}

var cat = new Cat();
console.log(cat.say());
//dog想重新利用say方法
var dog  = {food:"bone"};
cat.say.call(dog);//I Love food is:bone

但是如果我们有一个对象 var dog = {food:”bone”},我们不想对它重新定义say方法,
那么我们可以通过call或apply用cat的say方法:cat.say.call(whiteDog);
所以,可以看出call和apply是为了动态改变this而出现的,当一个object没有某个方法,但是其他的有,我们可以借助call或apply用其它对象的方法来操作。

用的比较多的,通过document.getElementsByTagName选择的dom
节点是一种类似array的array。
它不能应用Array下的push,pop等方法。
我们可以通过:
var domNodes = Array.prototype.slice.call(document.getElementsByTagName(“*”));
这样domNodes就可以应用Array下的所有方法了。

六、参考

  1. https://www.zhihu.com/question/20289071
  2. http://www.jb51.net/article/49230.html