JS 函數(shù)

函數(shù)

js的函數(shù)時(shí)參數(shù)化的:

  • 函數(shù)的定義會包括一個(gè)稱為形參的標(biāo)識符列表洛姑,這些參數(shù)會像局部變量一樣工作
  • 函數(shù)調(diào)用會為形參提供實(shí)參的值
  • 函數(shù)使用它們實(shí)參的值來計(jì)算返回值湃缎,成為該函數(shù)調(diào)用表達(dá)式的值
  • 除了實(shí)參之外啦租,每次調(diào)用還會有另一個(gè)值——本次調(diào)用的上下文(就是this的值)
  • 如果函數(shù)掛載在一個(gè)對象上浪慌,作為對象的一個(gè)屬性趁桃,就稱它為對象的方法仑最,當(dāng)通過這個(gè)對象來調(diào)用函數(shù)時(shí)扔役,該對象就是此次調(diào)用的上下文,也就是該函數(shù)this的值

函數(shù)的定義

函數(shù)使用 function關(guān)鍵字來定義:
1警医、函數(shù)定義表達(dá)式
2亿胸、函數(shù)聲明語句

// 函數(shù)聲明
function init () {
  //do something
}
// 函數(shù)定義表達(dá)式
var init = function () {
   // do something
}
  • 函數(shù)聲明語句“被提前”
    可以在定義之前調(diào)用
init();
function init () { // }
  • 表達(dá)式定義
    要使用一個(gè)表達(dá)式方式定義的函數(shù)之前,必須把它賦值給一個(gè)變量预皇,變量的聲明提前了侈玄,但是給變量賦值是不會提前的,所以定義之前是無法調(diào)用的
init(); // 報(bào)錯(cuò)   init is not a function 
var init = function () {};
init(); // 成功調(diào)用

函數(shù)命名

  • 通常以動詞或以動詞為前綴的詞組
  • 通常第一個(gè)字符為小寫(編程約定)
  • 當(dāng)函數(shù)名包含多個(gè)參數(shù)時(shí)吟温,或以下劃線分割序仙,或者駝峰
  • 內(nèi)部函數(shù)或私有函數(shù),通常以下劃線為前綴
  • 經(jīng)常調(diào)用的函數(shù)指定短名稱

函數(shù)調(diào)用

定義函數(shù)并不會執(zhí)行鲁豪,只有調(diào)用該函數(shù)時(shí)潘悼,它們才會執(zhí)行律秃,有4種方式調(diào)用:
1、作為函數(shù)
2治唤、作為方法:保存在一個(gè)對象的屬性里的js函數(shù)
3棒动、作為構(gòu)造函數(shù)
4、通過它們的call()apply()方法間接調(diào)用
任何函數(shù)只要作為方法調(diào)用實(shí)際上都會傳入一個(gè)隱式的的實(shí)參——這個(gè)實(shí)參是一個(gè)對象宾添,方法調(diào)用的母體就是這個(gè)對象船惨。

  • this是一個(gè)關(guān)鍵字,不是變量缕陕,也不是屬性名粱锐,不允許給它賦值
  • this沒有作用域限制,嵌套的函數(shù)不會從調(diào)用它的函數(shù)中繼承this
  • 如果嵌套函數(shù)作為方法調(diào)用扛邑,其this的值指向調(diào)用它的對象怜浅。
  • 如果嵌套函數(shù)作為函數(shù)調(diào)用,this值不是全局對象(非嚴(yán)格模式)就是undefined(嚴(yán)格模式下)
var o = {
  m:function () {                  // 掛載在對象上的方法 m()
    var self = this;              //  將this的值保存至一個(gè)變量中
    console.log(this === o);     // => true this 就是當(dāng)前這個(gè)對象 o
    f();
    function f () {             // 定義一個(gè)嵌套函數(shù)f()
      console.log(this);       // => Window
      console.log(this === o); // => false  this 的值是全局對象或者undefined
      console.log(self === o); // => true self 變量保存的是外部函數(shù)的this
    }
  }
}
var w = function () {
  console.log('w',this); // => 輸出對象o
  console.log(o === this); // => true 
}
o.n = w;
o.n(); 
o.m();

構(gòu)造函數(shù)調(diào)用
如果函數(shù)或者方法調(diào)用之前帶有關(guān)鍵字new鹿榜,它就構(gòu)成構(gòu)造函數(shù)調(diào)用

  • 凡是沒有形參的構(gòu)造函數(shù)調(diào)用都可以省略括號
var o = new Object();
var o = new Object;  // 凡是沒有形參的構(gòu)造函數(shù)調(diào)用都可以省略括號
  • 構(gòu)造函數(shù)調(diào)用創(chuàng)建一個(gè)新的空對象海雪,這個(gè)對象繼承自構(gòu)造函數(shù)的prototype屬性锦爵,構(gòu)造函數(shù)試圖初始化這個(gè)新創(chuàng)建的對象舱殿,并將這個(gè)對象用作其上下文,因此構(gòu)造函數(shù)可以使用this來引用這個(gè)新創(chuàng)建的對象险掀。
var o = {
  m:function (x) {                 // 掛載在對象上的方法 m()
    var self = this;              //  將this的值保存至一個(gè)變量中
    console.log(this);           // 輸出的是對象d
    console.log(this.w);        // => undefined 對象d在調(diào)用構(gòu)造函數(shù)的時(shí)候還未添加屬性 w
    console.log(this === o);   // => false 此時(shí)this是調(diào)用構(gòu)造函數(shù)創(chuàng)建的d
    this.x = x;                 // => 調(diào)用構(gòu)造函數(shù)創(chuàng)建對象時(shí)添加的參數(shù)沪袭,給新創(chuàng)建對象指定 屬性 x 并為其復(fù)制
    f();
    function f () {             // 定義一個(gè)嵌套函數(shù)f()
      console.log(this === o); // => false this的值是全局對象或者undefined
      console.log(self === o); // => false 對象 d
      console.log(this);       // => Window 對象
    }
  }
}
var d  = new o.m(1);        // 通過構(gòu)造函數(shù)創(chuàng)建一個(gè)新對象
d.w = "scp"
console.log(d.x);           // => 1 調(diào)用構(gòu)造函數(shù)時(shí)添加的屬性值

實(shí)參列表(arguments)

  • 標(biāo)識符arguments是指向?qū)崊ο蟮囊茫瑢?shí)參對象是一個(gè)類數(shù)組對象樟氢,可以通過數(shù)字下標(biāo)就能訪問傳入函數(shù)的實(shí)參值冈绊,而不用非要通過名字來得到實(shí)參。
init(1,2,3)
function init(){
  console.log(arguments[0]); // => 1
  console.log(arguments[1]); // => 2
  console.log(arguments[2]); // => 3
}
  • arguments包含一個(gè)length屬性埠啃,用以標(biāo)識其所包含元素的個(gè)數(shù)死宣。
init(1,2,3);
function init () {
  console.log(arguments.length); // => 3 傳入三個(gè)參數(shù)
}
  • 實(shí)參對象讓函數(shù)可以操作任意數(shù)量的實(shí)參。
    如下函數(shù)可以接收任意個(gè)數(shù)的實(shí)參碴开,稱為“不定實(shí)參函數(shù)”
max(1,2,3,100);
function max () {
  var max = Number.NEGATIVE_INFINITY; // 負(fù)無窮
  for (var i = 0; i < arguments.length; i ++) {
    if (arguments[i] > max) {
      max = arguments[i];
    }
  }
  return max;
}
// 
Math.max(1,2,3,100);
  • calleecaller屬性
    1毅该、ES5嚴(yán)格模式中,這倆屬性的讀寫操作都會產(chǎn)生類似錯(cuò)誤
    2潦牛、非嚴(yán)格模式下眶掌, callee屬性指代當(dāng)前正在執(zhí)行的函數(shù)
    3、callee屬性在某些時(shí)候回非常有用巴碗,比如在匿名函數(shù)中通過callee來調(diào)用自身
var init = function () {
  if (arguments.length < 2){
    arguments.callee(1,2)
  }
  console.log(arguments.length); // => 1   2
}
init(1);

閉包

首先回顧一下變量 作用域 和 作用域鏈

  • 全局變量擁有全局作用域
  • 在函數(shù)內(nèi)聲明的變量只在函數(shù)體內(nèi)有定義朴爬,它們是局部變量,作用域是局部性的
  • 函數(shù)參數(shù)也是局部比那里橡淆,它們只在函數(shù)體內(nèi)有定義
  • 在函數(shù)體內(nèi)召噩,局部變量的優(yōu)先級高于同名的全局變量母赵,如果在函數(shù)體內(nèi)聲明的一個(gè)局部變量或者函數(shù)參數(shù)中帶有的變量和全局變量重名,那么全局變量就被局部變量所遮蓋具滴。
  • 聲明局部變量必須使用var市咽,否則會認(rèn)為是什么一個(gè)全局變量或者修改全局變量
var a = 'global';   // 全局變量
function init () {
  var a = 'local';  // 同名的局部變量
  console.log(a); // => "local"
}
init();
  • 函數(shù)定義是可以嵌套的,由于每個(gè)函數(shù)都有自己的作用域抵蚊,因此會出現(xiàn)幾個(gè)局部作用域嵌套的情況施绎。
var a = 'global';   // 全局變量
function init () {
  var a = 'local';  // 同名的局部變量

  console.log(a); // => local
  
  function n (){
    var a = 'n local';
    console.log(a); // => n local
  }
}
init();

函數(shù)作用域和聲明提前

  • js使用函數(shù)作用域:變量在聲明它們的函數(shù)體以及這個(gè)函數(shù)體嵌套的任意函數(shù)體內(nèi)都是有定義的。
  • js的函數(shù)作用域是指在函數(shù)內(nèi)聲明的所有變量在函數(shù)體內(nèi)始終是可見的贞绳,這意味著變量在聲明之前甚至已經(jīng)可用谷醉,js的這個(gè)特性被非正式的稱為“聲明提前”
var a = 'global';    // 聲明一個(gè)全局變量
function f () {
  console.log(a);  // => "undefined" 并沒有輸出“global”
  var a = 'local';    // 變量在這里聲明并賦值,但是變量在函數(shù)體內(nèi)任何地方都是有定義的
  console.log(a); // => "local"
}
// 如上 等價(jià)于
function f () {
  var a;                  //   在函數(shù)頂部聲明了局部變量
  console.log(a);  //   變量存在冈闭,但是未賦值俱尼,所以值是undefined
  a = "local";        //   對局部變量進(jìn)行賦值
  console.log(a); //   => "local"
}

作用域鏈
變量取值是到創(chuàng)建這個(gè)變量的函數(shù)作用域中取值,如果當(dāng)前作用域沒有取到值萎攒,就會到上一級作用域去查遇八,直到查到全局作用域,這么一個(gè)查找的過程形成的鏈條就叫作用域鏈

  • 最終沒有查到會拋出異常
var a = 1;
function i_a () {
  var b = 2;
  function i_b () {
    var c = 3;
    console.log(a + b + c);     // => 6
  }
  i_b(); 
}
i_a(); 
  • ai_b作用域中并不存在耍休,此時(shí)就會到上一級作用域i_a中查到刃永,i_a中也不存在變量a,那么就再往上一級到全局中查到了a取值成功羊精。

閉包

  • 函數(shù)執(zhí)行依賴于變量作用域斯够,這個(gè)作用域是在函數(shù)定義時(shí)決定的
  • 函數(shù)嵌套
  • 一個(gè)函數(shù)訪問另一個(gè)函數(shù)的作用域
  • 閉包無處不在,js編寫幾乎時(shí)刻都在發(fā)生一個(gè)函數(shù)訪問另一個(gè)函數(shù)的作用域

利用閉包實(shí)現(xiàn)私有屬性的讀寫

function counter(){
  var n = 0;
  return {
    count:function(){
        return n++;
    },
    reset:function(){
        n = 0;
    }
  }
}
var c = counter();
console.log(c.count()); // => 0
console.log(c.count()); // => 1
c.reset(); // 重置變量
console.log(c.count());  // => 0

函數(shù)屬性喧锦、方法和構(gòu)造函數(shù)

length屬性

  • arguments.length表示實(shí)參個(gè)數(shù)
  • 函數(shù)本身的length屬性是只讀屬性读规,代表函數(shù)的形參數(shù)量
function counter(x){
    var arg_length = arguments.length;
    var ex_length = arguments.callee.length;

    console.log("arg_length:",arg_length); // => 2 實(shí)際傳入兩個(gè)參數(shù)
    console.log("ex_length:",ex_length); // => 1 定義函數(shù)時(shí)定義了一個(gè)參數(shù)
}
counter(1,1);

prototype屬性

每個(gè)函數(shù)都包含一個(gè)prototype屬性,這個(gè)屬性是指向一個(gè)對象的引用燃少,這個(gè)對象稱做“原型對象”束亏,每個(gè)函數(shù)都包含不同的原型對象,當(dāng)將函數(shù)做構(gòu)造函數(shù)的時(shí)候阵具,新創(chuàng)建的對象會從原型對象上繼承屬性碍遍。

方法的prototype屬性

function counter () {
}
var c = new counter();

call()方法和apply()方法

  • call()apply()的第一個(gè)實(shí)參是要調(diào)用函數(shù)的母對象,它是調(diào)用上下文怔昨,在函數(shù)體內(nèi)通過this來獲取對它的引用雀久。
    通俗來講第一個(gè)參數(shù)是誰要調(diào)用函數(shù)
var o = {
  name:"my name is o"
}
function f () {
  console.log(this);   // => {name: "my name is o"} 此時(shí)this指向調(diào)用者o
  console.log(this.name); // => "my name is o"
}
f.call(o);
f.apply(o); // 倆個(gè)調(diào)用結(jié)果是一樣的
  • call()的參數(shù)直接方進(jìn)去的料祠,第二第三第 n個(gè)參數(shù)全都用逗號分隔
var o = {
    name:'my name is o'
}

function counter(){
    console.log(arguments.length); // => 2 傳入兩個(gè)參數(shù)
    console.log(this.name);  // => 'my name is o'
    console.log("my height is " + arguments[0] + 'cm'); // => 'my height is 180cm'
    console.log("my weight is " + arguments[1] + 'kg'); // => 'my weight is 70kg'
}
counter.call(o,180,70);
  • apply()的所有參數(shù)必須放在一個(gè)數(shù)組里傳入
counter.apply(o,[180,70]);

bind()方法

bind()用來將函數(shù)綁定至某個(gè)對象丑瞧。

function f() {
  return this.x + 1;
}
var o = {x:1};
f.bind(o)(); // => 輸入2 會把f當(dāng)做o的方法來調(diào)用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末墓卦,一起剝皮案震驚了整個(gè)濱河市步清,隨后出現(xiàn)的幾起案子馆类,更是在濱河造成了極大的恐慌罐呼,老刑警劉巖壹店,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诺舔,死亡現(xiàn)場離奇詭異,居然都是意外死亡卤唉,警方通過查閱死者的電腦和手機(jī)涩惑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來桑驱,“玉大人竭恬,你說我怎么就攤上這事“镜模” “怎么了痊硕?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長押框。 經(jīng)常有香客問我岔绸,道長,這世上最難降的妖魔是什么橡伞? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任盒揉,我火速辦了婚禮,結(jié)果婚禮上兑徘,老公的妹妹穿的比我還像新娘刚盈。我一直安慰自己,他們只是感情好道媚,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布扁掸。 她就那樣靜靜地躺著,像睡著了一般最域。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锈麸,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天镀脂,我揣著相機(jī)與錄音,去河邊找鬼忘伞。 笑死薄翅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的氓奈。 我是一名探鬼主播翘魄,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼舀奶!你這毒婦竟也來了暑竟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤育勺,失蹤者是張志新(化名)和其女友劉穎但荤,沒想到半個(gè)月后罗岖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腹躁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年桑包,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纺非。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡哑了,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出烧颖,到底是詐尸還是另有隱情垒手,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布倒信,位于F島的核電站科贬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鳖悠。R本人自食惡果不足惜榜掌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乘综。 院中可真熱鬧憎账,春花似錦、人聲如沸卡辰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽九妈。三九已至反砌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間萌朱,已是汗流浹背宴树。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晶疼,地道東北人酒贬。 一個(gè)月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像翠霍,于是被迫代替她去往敵國和親锭吨。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 在js中寒匙,函數(shù)本身屬于對象的一種零如,因此可以定義、賦值,作為對象的屬性或者成為其他函數(shù)的參數(shù)埠况。函數(shù)名只是函數(shù)這個(gè)對象...
    bjhu電net閱讀 528評論 0 5
  • 函數(shù)和對象 1耸携、函數(shù) 1.1 函數(shù)概述 函數(shù)對于任何一門語言來說都是核心的概念。通過函數(shù)可以封裝任意多條語句辕翰,而且...
    道無虛閱讀 4,543評論 0 5
  • 1. 函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別 (*) 函數(shù)在JS中有三種方式來定義:函數(shù)聲明(function decla...
    進(jìn)擊的阿群閱讀 439評論 0 1
  • 函數(shù)只定義一次夺衍,但可能被執(zhí)行或調(diào)用任意次。JS函數(shù)是參數(shù)化的喜命,函數(shù)的定義會包括一個(gè)稱為形參的標(biāo)識符列表沟沙,這些參數(shù)在...
    PySong閱讀 519評論 0 0
  • 函數(shù)只定義一次,但可能被執(zhí)行或調(diào)用任意次壁榕。JS函數(shù)是參數(shù)化的矛紫,函數(shù)的定義會包括一個(gè)稱為形參的標(biāo)識符列表,這些參數(shù)在...
    PySong閱讀 310評論 0 0