函数

1. 函数声明
function funcName(){
        ...
    }

由于声明提前,可以在定义之前调用此函数。不能出现在循环,条件判断,或者try/catch/finally以及with语句里。

此外,要注意函数内的的变量声明也是会提前的。这里经常笔面试出题。

var scope="global";
    function scopeTest(){
        console.log(scope);
        var scope="local"; //scope变量提前到console.log语句前。
    }
    scopeTest(); //undefined
2. 函数表达式(函数名可选,在递归时通常会写函数名)
var f = function(){
        ...
    }

不能在定义之前调用。

函数调用及其调用上下文

1. 作为函数

非严格模式下,调用上下文(this值)是全局对象,严格模式下,调用上下文是undefined.

2. 作为方法

调用上下文和与函数调用不同。指的当前对象,而不是全局对象。

var o = { // An object o.
        m: function() { // Method m of the object.
            var self = this; // Save the this value in a variable.
            console.log(this === o);  // 1.Prints "true": this is the object o.
            f(); // 作为函数调用,因此其调用上下文是全局对象或者undefined。所以2的结果为false
            function f(){ // A nested function f
                console.log(this === o); // 2."false": this is global or undefined
                console.log(self === o);// 3."true": self is the outer this value.
            }
        }
    };
    o.m();// 作为方法调用,其调用上下文为当前对象。因此1的结果为true。

当方法的返回值是对象时,对象还可调用其方法,行成方法链。就像jQuery一样。

var ob = {
        m: function(a) {
            console.log(a);
            return this;
        },
    }
    ob.m(5).m(6);
3. 作为构造函数

函数/方法前带有关键字new,就构成了构造函数调用。

构造函数调用创建一个新的空的对象,这个对象继承自构造函数的prototype属性。构造函数的调用上下文为新创建的对象。

构造函数通常不用return关键字,通常返回的是新创建的的对象的值。比如熟悉的var obj = new Object;

当构造函数显式地使用return语句返回对象时,返回的就是该对象;如果返回的是原始值,则跟没有显式使用return是一样的。

function test1(a,b,c){
      this.a = a;
      this.b = b;
      return c; //returns a primitive value
      }

    //Results
    > var x = new test1(4,5,6);
    undefined
    > x
    { a: 4, b: 5 }
function test2(a,b){
      this.a = a;
      this.b = b;
      return {1:2}; //returns an object
    }
    //Results
    > var y = new test2(7,8);
    undefined
    > y
    { '1': 2 }
4. 通过call(),apply()间接调用

第一个实参是要调用函数的母对象,它是调用上下文f.call(o)以及f.apply(o)的意思是:以对象o的方法来调用f函数。

严格模式下,第一个实参都会变成this的值,哪怕传入的实参是原始值/null/undefined

非严格模式下,传入的null/undefined会被全局变量代替。

apply和call的区别在于传入实参的形式不同,比如apply(o,[x,y,z...])call(o,x,y,z,...)