fred-ye / summary

my blog
43 stars 9 forks source link

[JavaScript] 函数的总结 #54

Open fred-ye opened 8 years ago

fred-ye commented 8 years ago

Javacript中的函数

函数的调用方式

var add = function (a, b) { return a + b; };
var sum = add(3, 4); 
var myObject = {
    value: 0,
    increment: function (inc) {
        this.value += typeof inc === 'number' ? inc : 1;}
};
myObject.increment(); 
document.writeln(myObject.value); 
var Quo = function (string) {
    this.status = string;
}
Quo.prototype.get_status = function () {
    return this.status;
}
var myQuo = new Quo("confused");
console.log(myQuo.get_status());

当我们将函数作为构造器使用时,通常将函数名大写

var Quo = function (string) {
    this.status = string;
}
Quo.prototype.get_status = function () {
    return this.status;
}
var myQuo = new Quo("confused");
console.log(myQuo.get_status());
var statusObject = {
    status: 'A-OK'
};
Quo.prototype.get_status.apply(statusObject);//输出"A-OK"

函数的参数

arguments属性

var sum = function (){
    var i, sum = 0;
    for ( i = 0; i < arguments.length; i = i + 1) {
        sum += arguments[i];
    }
    return sum;
}
console.log(sum(4, 5, 6));

预定义函数

一些常见的预定义函数 parseInt, parseFloat, isNaN, isFinite, encodeURI, encodeURIComponent, decodeURI, decodeURIComponent, eval

变量的作用域

JavaScript 的作用域完全是由函数来决定的,if、for语句中的花括号不是独立的作用域。

if (true) {
    var somevar = 'value';
}
console.log(somevar); // 输出 value

在函数中引用一个变量时,JavaScript会先搜索当前函数作用域,或者称为“局部作用域”,如果没有找到则搜索其上层作用域,一直到全局作用域。

var scope = 'global';
var f = function() { 
    console.log(scope); // 输出 undefined 
}
f();

上面代码没有输出global,而是undefined。 这是JavaScript的一个特性,按照作用域搜索顺序,在console.log函数访问scope变量时,JavaScript会先搜索函数f的作用域,恰巧在f 作用域里面搜索到scope变量,所以上层作用域中定义的scope 就被屏蔽, 但执行到console.log语句时,scope还 没被定义,或者说初始化,所以得到的就是undefined值了。

变量提升

看一个例子:

var a = 123;
function f() {
    alert(a); //undefined
    var a = 1;
    alert(a); //1
}
f();

说明:当JavaScript执行过程进入新的函数时,这个函数内被声明的所有变量都会被移动(或者说提升)到函数最开始的地方。但是需要注意的是,提升的只是函数的声明。也就是说函数体内声明的这些变量在该函数执行开始时就存在,而与之相关的赋值操作并不会提升,还在其原来的位置上。

即时函数

立即执行的函数,其写法如下:

(function() {
    alert('-----exec------')
})();

也可以

(function() {
    alert('-----exec------')
}());

参数的传递

(function(data) {
    alert(data)
}('-----exec------'));

获取即时函数的返回值

var result = (function() {return 5;}());
alert(result); // 5

即时函数的好处是不会产生作何全局变量,所以在很多js框架会用到,避免对其它的框架的变量污染。缺点在于这样的函数是无法重复执行,这使得即时函数非常适合于执行一些一次性的或初始化的作务。

异常的捕获

try ... catch

var add = function (a, b) {
    if (typeof a !== 'number' || typeof b != 'number') {
        throw {
            name: 'TypeError',
            message: 'add needs numbers'
        };
        return a + b;
    }
}
var try_it = function () {
    try {
        add('seven');
    } catch (e) {
        console.log('Exception:' + e.name + ':' + e.message);
    }
}
try_it();

闭包

闭包:内部函数可以访问外部函数中定义的所有属性。 一个例子:

var myObject = function () {
    var value = 0;
    return {
        increment: function (inc) {
            value += typeof inc === 'number' ? inc : 1;
        },
        getValue: function() {
            return value;
        }
    };
}();

我们赋给myObject的不是一个函数,还是一个对象。这个对象包含两个函数,这种方式保护了内部的属性value.

循环中的闭包

我们的目的是:有一个三次的循环操作,每次迭代中都会创建一个返回当前循环序号的新函数,该新函数会被添加到一个数组中,并最终返回。

function F() {
    var arr = [], i;
    for (i = 0; i < 3; i ++) {
        arr[i] = function() {
            return i;
        }
    }
    return arr;
}

> var arr = F();
> arr[0](); // 3
> arr[1](); // 3 
> arr[2](); // 3

如果觉得这个不太好理解,可以先看这么个例子

function F(param) {
    var N = function () {
        console.log('param:' + param);
        return param;
    };
    param ++;
    return N;
}
> var inner = F(123);
> inner(); // 124

当执行F(123)时,N被赋值,同时param ++执行,当执行inner()时,由于已执行过param ++,此时,param的值是124

再回到上面一个例子。原理是一样的,当执行F()时,arr[i]被赋值,这里创建了三个闭包,都指向一个共同的局部变量i, 但是闭所并不会记录它们的值。对于这三个函数(闭包)中的作何一个而言,当它要去获取某个变量时,会从其所在的域开始逐级寻找那个距离最近的i 值。当循环结束时i的值为3, 所以这三个函数都指向了这一共同值。

如果想达到我们最初的目的,可以采用即时函数,不再直接创建一个返回i的函数,而是将i传递给了另一个即时函数,在该函数中,i就补被赋值给了局部变量x, 这样一来,每次迭代中的x就会拥有各自不同的值。

function F() {
    var arr = [], i;
    for (i = 0; i < 3; i ++) {
        arr[i] = (function(x) {
            return function() {
                return x;    
            }
        }(i));
    }
    return arr;
}
> var arr = F();
> arr[0](); // 0
> arr[1](); // 1
> arr[2](); // 2

如果不使用即时函数

function F() {
    function binder(x) {
        return function() {
            return x;
        };
    }
    var arr = [], i;
    for (i = 0; i < 3; i ++) {
        arr[i] = binder(i);
    }
    return arr;
}

每次迭代时,在中间函数内将i的值“本地化”.

应用--迭代器

function setup(x) {
    var i = 0;
    return function () {
        return x[i++];
    };
}

> var next = setup(['a', 'b', 'c']);
> next(); //a
> next(); //b

this

记住一点,函数中的this是当前的调用者。一个例子:

var name = "The Window";
var object = {
    name : "My Object",
  getNameFunc : function(){
    return function(){
        return this.name;
    };
  }
};
alert(object.getNameFunc()()); // The Window
var name = "The Window";
var object = {
  name : "My Object",
  getNameFunc : function(){
    var that = this;
    return function(){
      return that.name;
    };
  }
};
alert(object.getNameFunc()());