亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

函數(shù)的實參 函數(shù)的形參 閉包 js

huhud / 1946人閱讀

摘要:不在任何函數(shù)內聲明的變量為全局變量。加變成一個函數(shù)表達式,解釋器運行創(chuàng)建一個匿名的函數(shù)表達式閉包終于到閉包了。

函數(shù)的實參和形參

可選形參
if(a === undefined) a = [];

等價于

a = a || [];

這兩句是完全等價的,只不過后者需要提前聲明a而已
如果參數(shù)沒有傳入,其余的填充undefined
可選的形式參數(shù):通過注釋/optional/來強調參數(shù)可選,并且要將其放在最后,否則就要使用null或者undefined來作為占位符來進行傳入

可變長的實參列表 callee和caller

callee為指代當前正在執(zhí)行的函數(shù)
caller指代當前正在執(zhí)行函數(shù)的函數(shù)

將對象屬性用作實參
>
> function e(o){
...   return o.Object;
... }
undefined
> e;
[Function: e]
> var a = {Object:33};
undefined
> e(a);
33
>
作為值的函數(shù)

函數(shù)能作為值傳入另外一個函數(shù)

自定義函數(shù)屬性

函數(shù)屬性可以自定義

o.a = 3;
function o() {
  return o.a;
}

作為命名空間的函數(shù)

在函數(shù)中聲明的變量在整個函數(shù)體內都是可見的(包括在嵌套函數(shù)中),在函數(shù)外部是不可見的。不在任何函數(shù)內聲明的變量為全局變量。在整個js程序中都是可見的。在js中無法聲明只在一個代碼塊內可見的變量的。所以常常簡單的定義一個函數(shù)用作臨時的命名空間。在這個命名空間內定義的變量都不會污染到全局命名空間。
正是因為如果將變量定義在全局的時候,會出現(xiàn)變量的污染,污染到全局變量(好吧,這是動態(tài)語言的坑)導致出現(xiàn)一些未知的錯誤。所以呢將變量放置在函數(shù)中,在進行調用,這樣放置其變量污染其全局空間,出現(xiàn)變量的沖突(尤其是在瀏覽器的環(huán)境下,很容易的,導致各種未知錯誤,所以必須要這樣做)

定義完函數(shù)后直接調用函數(shù)
(
  function() {
    return 333;
  }()
);

加()是必須的,因為如果不加()會讓js解釋器認為其為函數(shù)聲明,function按照函數(shù)聲明來進行解釋,js解釋器不允許創(chuàng)建一個匿名的函數(shù)聲明,所以會報錯。
加()變成一個函數(shù)表達式,js解釋器運行創(chuàng)建一個匿名的函數(shù)表達式

閉包

終于到閉包了。(正經(jīng)點Σ( ° △ °|||)︴)
(這是最難的地方,是函數(shù)式編程的基礎,也是能否學好js的最關鍵的地方。。。。當然了,es6還有一個令人討厭的箭頭函數(shù))
閉包是其函數(shù)式編程的重要的基礎
和其他語言一樣js采用的詞法作用域,即函數(shù)的執(zhí)行依賴于變量的作用域,作用域是在函數(shù)定義時確定的,不是在其調用所決定的
即js的函數(shù)對象的內部狀態(tài)不僅僅包含函數(shù)的代碼邏輯,還必須引用當前的作用域鏈(變量的作用域向下傳遞的,變量的作用域鏈在進行尋找的時候往上尋找,直到函數(shù)的頂部)函數(shù)對象可以通過作用域鏈相互關聯(lián)起來,函數(shù)體內部的變量可以保存在函數(shù)作用域內,即閉包

很古老滴術語,指函數(shù)變量可以被隱藏于作用域鏈之內,因此看起來函數(shù)將變量包裹起來。
如何定義作用域鏈

作用域鏈為一個對象的列表,每次調用js函數(shù)的時候,都會創(chuàng)建一個新的對象來保存其局部變量,把這個對象添加到作用域鏈中,如果函數(shù)返回,就從作用域鏈中將綁定的對象刪除,如果不存在嵌套函數(shù),也不存在其引用指向這個綁定的對象,會被js解釋器的垃圾回收機制不定時的回收,是不定時的,不是在沒有完全引用的時候立馬刪除,如果定義了嵌套函數(shù),每個嵌套函數(shù)都各自對應著一個作用域鏈,并且這個作用域鏈指向一個變量綁定的對象。如果這些嵌套函數(shù)對象在外部函數(shù)中保存下來,那么他們也會和所指向的變量綁定對象一樣當做垃圾進行回收,如果這個函數(shù)定義了嵌套的函數(shù),并將它作為返回值返回,或者存儲在某處屬性里,會有外部引用指向這個嵌套函數(shù),即不會被當做垃圾回收,其變量所綁定的對象也不會當做垃圾進行回收。

函數(shù)執(zhí)行完畢以后相關的作用域鏈不會刪除,只有當不在有引用的時候,才會進行刪除操作

關于棧的說明

原始棧
棧頂 window
執(zhí)行下列js腳本

function a() {
  function f() {
    return 333;
  }
  return f;
}
a()();

棧頂 a → window
開始調用,執(zhí)行到return
發(fā)現(xiàn)需要調用f
繼續(xù)加棧
棧頂 f → a → window
執(zhí)行完f彈出f
繼續(xù)執(zhí)行a,執(zhí)行完畢彈出a
最后全部執(zhí)行完畢彈出window

算了文字解釋太無力,直接上代碼

var scope = "global scope"; // 一個全局變量
function checkscope() 
{
  
  var scope = "local scope";  // 定義一個局部變量
  
  function f() 
  {
    return scope; // 返回變量作用域中的scope的值
  }
  
  return f(); // 返回這個函數(shù)
}

調用一下這個函數(shù)

checkscope();
"local scope"

接著這樣執(zhí)行

var scope = "global scope"; // 一個全局變量
function checkscope() 
{
  
  var scope = "local scope";  // 定義一個局部變量
  
  function f() 
  {
    return scope; // 返回變量作用域中的scope的值
  }
  
  return f; // 返回這個函數(shù)
}

繼續(xù)調用函數(shù)

checkscope()();
"local scope"
閉包有什么用

先看一個函數(shù)uniqueInteger()使用這個函數(shù)能夠跟蹤上次的返回值

var uniqueInteger = (
  function() {
    var count = 0;
    return function() {return count++}
  }()
);

這樣子就使用閉包

uniqueInteger();
0
uniqueInteger();
1

每次返回是其上一次的值,并隨便直接將值加1
至于為什么要這樣寫,如果不使用閉包,那么惡意代碼就可以隨便的將計數(shù)器重置了。。

uniqueInteger.count = 0;
function uniqueInteger() {
  return uniqueInteger.count++;
}

類似這樣的,完全可以做到直接通過賦值,將其count的值重置。
而如果使用閉包,沒有辦法進行修改,為私有狀態(tài),也不會導致其一個頁面內變量的沖突,或者是其覆蓋。

立即調用的函數(shù)
var a = (function c(){
  var a = 1;
  a++;
  console.log("已經(jīng)執(zhí)行");
  return function b(){return a++};
}())

額,我大概解釋一下這段代碼。
首先呢,解釋最外層的圓括號,因為如果沒有圓括號,則這個是一個賦值語句,將一個匿名函數(shù)賦值給變量a,實際上是在內存中完成了棧中變量a指向匿名函數(shù)存儲的空間的地址,如果有圓括號,實際上是告訴js解釋器這是一個語句,需要js執(zhí)行,消除了其function帶來的影響。(ps;貌似火狐上不加也可以,也可以正常的運行)執(zhí)行和引用的關系下方有。
然后呢,最后的圓括號,代表著其執(zhí)行這個函數(shù),因為js解析器將()解析為調用前方的函數(shù)名稱,類似于運算符吧。但是實際上并不是運算符,因為能往其內傳值,注意,這點是將其執(zhí)行的結果保存在堆中,并完成其指向
其后,當直接輸入a;,實際上執(zhí)行并完成了一次調用,其返回值為函數(shù)b,將函數(shù)b完成一次引用,即變量a引用函數(shù)b,由于其存在引用關系,即棧中變量a保存的為其函數(shù)a的返回結果,(因為其不是不是對象,如果寫a()()表示將函數(shù)a調用后返回的對象保存在棧中,然后將棧中的內容再次調用,由于是保存,并不存在其應用關系,所以執(zhí)行完畢后直接垃圾回收)由于其保存的是函數(shù)b的作用域鏈,而函數(shù)b的作用域鏈是繼承自函數(shù)a的作用域鏈,但是由于函數(shù)a的作用域鏈并沒有引用導致其執(zhí)行完后被垃圾回收(當不在有變量指向的時候)。所以呢,函數(shù)其值是在函數(shù)b中進行保存,如果修改函數(shù)c此時函數(shù)c并不會影響到函數(shù)b中的保存,因為其函數(shù)c的變量列表已被銷毀,
最后,繼續(xù)討論起嵌套函數(shù)的引用,由于其父函數(shù)已被銷毀,但是嵌套函數(shù)被引用,(注意:因為其父已經(jīng)沒有,所以是另開辟一塊新的堆空間,用于存儲其函數(shù)c的返回結果,注意是返回結果,而不是函數(shù)b)此時另外指定變量保存其結果,無論指定多少個變量保存其結果,都是新的空間的執(zhí)行,沒有任何的干擾,詳細了解看下面,繼續(xù)討論

ps;如果是()()則代表其會被其垃圾回收

ps 還需要注意一點點的是由于其引用的是result的值,并不是其

最后,這樣就能完成其變量保存在函數(shù)中,貌似叫做記憶?

所以呢,借助堆和棧就很好的能理解了閉包

再繼續(xù)看代碼
function count() {
  var n = 0;
  return {
    count: function() { return n++; },
    reset: function() { n = 0; }
  };
}
var c = count(); var d = count();
undefined

在分別執(zhí)行一下下

c.count();
0
d.count();
0
c.count();
1
d.count();
1
c.reset();
undefined
c.count();
0
d.count();
2

這一點體現(xiàn)了其互不影響性,表明其由于其父被回收,導致其子分別開創(chuàng)了一塊在堆中新的內存空間,并完成其指向,互相不干擾。
其作用域鏈互不干擾

使用getter和setter完成其閉包
function count(n) {
  return {
    get count() { return n++; },
    set count(m) { 
      if ( m >= n)
        n = m;
      else
        throw new Error( "請輸入一個正確的值" );
    },
  };
}

這個就不用解釋啦,很簡單啦

同一個作用域鏈中定義兩個閉包
function test1() {
  val = value = 111;
  this.test = function() { return value - 1; };
  this.test2 = function() { return value + 1; };
  
}

這同樣是兩個作用鏈域
不過這樣寫需要先執(zhí)行其o.test1(),因為其方法在其函數(shù)內部,必須先執(zhí)行一下,完成其方法的添加,否則會報錯,

ee.test is not a function

提示找不到這個方法,
因為執(zhí)行

ee.test1 = test1;
function test1()

只是簡單的進行賦值,并不能進行查看,所以導致其無法使用
所以嘛,要先執(zhí)行一遍,讓其方法添加進去

ee.test1();
undefined
ee.test();
110
ee.test2();
112

這就是兩個閉包,這兩個閉包互相平行,同時繼承于其父,但是又不受其父影響,很神奇吧,(@ο@)

叮 又發(fā)現(xiàn)一個莫名奇妙的東東 https://us.leancloud.cn 貌似目前水平能看懂一些了
關于this的問題

this在父閉包顯示的即為使用該方法的對象。
但是子就不一定了。

function test1() {
  val = value = 111;
  this.test = function() { return this.x - 1; };
  this.test2 = function() { return this.x + 1; };
}

執(zhí)行一下

ee.test();
4443

這就尷尬了。
好吧。只能說是一般不這樣用
一般這樣寫

var self = this;

將其值保存進一個self中

文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://www.ezyhdfw.cn/yun/96149.html

相關文章

  • JS語言核心——“函數(shù)

    摘要:比如,以對象的方法的形式調用函數(shù)并傳入兩個參數(shù)可以傳入的參數(shù)可以是數(shù)組和類數(shù)組的。方法的該方法主要作用是將函數(shù)綁定至某個對象,方法返回一個新的函數(shù),調用這個新的函數(shù)會把綁定的函數(shù)在對象中當做方法來調用。 參數(shù) 形參(parameter):函數(shù)中定義的變量 實參(argument):運行時的函數(shù)調用時傳入的參數(shù) 上下文(context):通過對象來調用函數(shù)時,這個對象就是thi...

    EsgynChina 評論0 收藏0
  • 翻譯連載 | JavaScript 輕量級函數(shù)式編程-第3章:管理函數(shù)輸入 |《你不知道JS》姊

    摘要:但是,對函數(shù)式編程而言,這個行為的重要性是毋庸置疑的。關于該模式更正式的說法是偏函數(shù)嚴格來講是一個減少函數(shù)參數(shù)個數(shù)的過程這里的參數(shù)個數(shù)指的是希望傳入的形參的數(shù)量。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關于譯者:這是一個流淌著滬江血液的純粹工程:認真,是 HTML 最堅實的梁柱;分享,是...

    xiaowugui666 評論0 收藏0
  • 犀牛書——CHAP8:函數(shù)

    摘要:若有函數(shù)名,則在函數(shù)體內指代該函數(shù)本身,并且只存在于函數(shù)體中。返回值與普通函數(shù)相同。如果嵌套函數(shù)作為普通函數(shù)調用,則指向全局對象或者構造函數(shù)調用在函數(shù)或者方法調用之前使用關鍵字,則為構造函數(shù)調用。創(chuàng)建一個新的對象繼承構造函數(shù)的屬性。 showImg(https://box.worktile.com/view/ddbade8c84bb41cdb20db15228584b8e?pid=4b...

    he_xd 評論0 收藏0
  • JavaScript || 函數(shù)

    摘要:每個函數(shù)表達式包括函數(shù)對象括號和傳入的實參組成。和作用都是動態(tài)改變函數(shù)體內指向,只是接受參數(shù)形式不太一樣。在定義函數(shù)時,形參指定為一個對象調用函數(shù)時,將整個對象傳入函數(shù),無需關心每個屬性的順序。 函數(shù) JavaScript中,函數(shù)指只定義一次,但可以多次被多次執(zhí)行或調用的一段JavaScript代碼。與數(shù)組類似,JavaScript中函數(shù)是特殊的對象,擁有自身屬性和方法 每個函數(shù)對象...

    learn_shifeng 評論0 收藏0
  • 講清楚之 javascript 函數(shù)

    摘要:中函數(shù)是一等公民。小明小明調用函數(shù)時,傳遞給函數(shù)的值被稱為函數(shù)的實參值傳遞,對應位置的函數(shù)參數(shù)名叫作形參。所以不推薦使用構造函數(shù)創(chuàng)建函數(shù)因為它需要的函數(shù)體作為字符串可能會阻止一些引擎優(yōu)化也會引起瀏覽器資源回收等問題。 函數(shù) 之前幾節(jié)中圍繞著函數(shù)梳理了 this、原型鏈、作用域鏈、閉包等內容,這一節(jié)梳理一下函數(shù)本身的一些特點。 javascript 中函數(shù)是一等公民。 并且函數(shù)也是對象,...

    Keagan 評論0 收藏0

發(fā)表評論

0條評論

huhud

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<