JavaScript特殊的對象2:函數

1、爲何說函數是特殊的「對象」呢?

1. 由於函數能夠經過Function()構造函數來定義:var f = new Function("x","y","return x*y;");java

2. 函數屬性:閉包

1)length(形參個數)app

2)prototype:每一個函數都有這個屬性!(引用)指向一個(原型)對象。每一個函數都會有,構造函數也有。因此用構造函數去建立對象的時候,這個對象的原型是 構造函數.prototype這個屬性的值。(這裏邊構造函數是對這個屬性作個賦值了的)函數

3. 函數方法:函數對象的兩個方法call()和apply();spa

2、函數的定義

1. 函數聲明語句

function f(x){}這個是函數聲明語句,它其實是聲明瞭一個變量f,並把一個函數對象:{} 賦值給它!
1) 這句話定義了一個變量名爲f。並給它賦值(即指向函數體{}):這個定義建立了一個函數對象,並將其賦值給變量f。函數的名字其實是可不見的,f僅僅是一個變量名而已,這個變量名指向(引用)函數對象。
2)無論這個函數聲明放在哪裏,它在整個腳本全局域裏均可見。由於這裏有提高的機制在裏面:函數名和函數體(賦值)均被提早到(頂部)。
這也是爲何能夠調用本身的緣由了。 
3) 不一樣於變量提高,變量提高只是把聲明提高,可是賦值定義卻沒有提高。
4.)函數聲明語句非真語句。不能插在任何語句之中。而函數定義表達式能夠出如今任何地方,由於他們自帶;分號本身自己就是語句了。.net

2. 函數表達式(匿名函數方式)

var f = function(x){};這是函數表達式(原始)
1)若是在這個表達式以前調用了f(x);會報錯。由於只提高了變量f的聲明,變量的賦值初始化也就是綁定函數對象沒有被提高,因此f仍是個undefined,還不具有函數性質。
2)當函數表達式加上了名稱  var a = function f(x){};實際上函數的名稱f將成爲函數內部的一個局部變量。prototype

3)function(x){}就是一個匿名函數那它怎麼調用呢?對象

A. 若是這裏,把他賦值給 f 。這樣f就能去引用它。因此咱們能夠直接用f(x)進行調用。blog

B. 自調用。把匿名函數整改放在這樣的表達式括號裏();並在這個表達式括號中匿名函數的尾部加上()就是自調用。(function(x){..}(3)); 或者(function(x){..})(3);繼承

C. 匿名函數最大的用途是建立閉包(這是JavaScript語言的特性之一),而且還能夠構建命名空間,以減小全局變量的使用。

3. 構造函數的方式

var f = new Function("x","y","return x*y;");

4. 當一個函數定義以後JavaScript會自動給這個函數的原型添加一個constructor屬性並並賦值這個函數的類。

3、函數調用

默認是undefined,若是有return something 就返回具體值,沒有return 也是undefined。

1. 自調用 (function(){}());——》b=function(){} ——》(b());——》b();

2. 

4、特殊函數

1. 構造函數(類)

首先第一個概念:類 就是構造函數,構造函數就是類  //不是java裏面的類裏面有構造函數。
var F = function(){};
var obj = New Object();
F.prototype = obj; //繼承其餘類
F.prototype.construtor = F;
//如今添加本身的
F.prototype.x = function(){...};
F.prototype.y = function(){...};
var f = new F();
f.construtor ——》F.prototype.construtor = F ——》f.construtor = F;
f.prototype = Object() 另外f還有自有屬性  x 和 y。

當不繼承任何人時
能夠是

var F = function(){....};
var f = New F();
F.prototype = {....} = f;
F.prototype.construtor = F;
F.prototype = f
f.construtor= F

2. 匿名函數與自調用

匿名匿名就是沒有名字的函數定義:function(){};

自調用:(function(){}());或者(function(){})();

 

2. 工廠函數

5、閉包和做用域鏈概念

1.  做用域鏈

1)首先咱們從全局出發<script>中,其實就是一個全局函數變量(若是C的main()函數同樣),咱們在其中定義的全部Function定義的函數(它裏面也有可能嵌套)也都是嵌套在這個全局函數而已,因此整個js代碼咱們能夠從某種程度上當作一系列的函數嵌套過程。既然有嵌套,隨之就是有嵌套深度,那,怎麼表現這個深度呢,咱們這裏就能夠用(函數對象)做用域鏈來表示。記住js和其餘語言不一樣,不是塊做用域,而是函數做用域。這條做用域上保存這個這些嵌套的函數對象,咱們能夠定義全局函數對象在做用域鏈中是第1層,隨着嵌套依次疊加。

2)函數調用時做用域鏈起到的做用:

做用域鏈在函數定義的時候決定的(也就是在定義這個函數的時候它的做用域隨之肯定,函數被綁定在上面)。調用時依賴這個做用域,因此什麼時候何地調用,它只會在這個做用域裏去找它須要的變量。若是函數定義是變量就在這個做用域上,它就跑不掉了(閉包)。就好像,一個家譜(做用域鏈)同樣,(函數)你生下來,就被寫進了一個家譜,無論你身在何方,中國仍是美國,你什麼時候何地均可以(打電話)問家裏(問爸媽問爺爺奶奶)要錢(變量)。可是不能跟同級的姐妹或者本身的子女要。

當函數調用須要找變量時,從自身出發(做用域鏈最高層)開始找,若是本身有了,就拿,沒有就會沿着做用域鏈一層層往下找,直到第0層(全局函數變量)爲止。

3)變量提高定義是在函數體內的聲明的全部變量在函數體內任何地方都是可見的。按照正常的習慣咱們如今函數頂部先var聲明好變量並定義好,可是有些「變量」比較調皮,沒有var聲明變量以前,它先在前面直接使用,可是後面它又想起來了,在函數後面補上var 並賦值。這是能夠的,由於js的規則是在所用函數執行以前,把全部變量的聲明都統一提高到函數頂部。(雖然js幫忙提高,也就只是聲明提高,咱們知道只聲明不賦值的變量是undefined,因此前面引用的那個會是undefined但若是沒有var聲明但賦值了,後面又追加聲明,它但是拿到賦值的值。只有在真正他想起來賦值的地方,這個變量纔算真正有意義)。

2. 閉包

1)(從全局開始一直嵌套)的全部函數對象能夠經過做用域鏈相互關聯起來,函數體內部的變量均可以保存在做用域內叫閉包。若是函數定義是變量就在某個做用域上,它就跑不掉了。什麼時候何地調用函數,它都能在本身相應的做用域鏈上找到本身所須要的變量。這個就是閉包在js中起到的做用。

 

1. 在函數中定義裏一個局部變量a和一個嵌套函數f()綁定在一塊兒,無論在什麼時候何地只要能調用到f(),就必定用到這個變量a。這樣的a變量咱們能夠叫私有變量。
2. 如何把兩個閉包放在一個做用域中,而後能共享一樣的私有變量?

7、call()和apply()和bind()(點擊可查看)

相關文章
相關標籤/搜索