摘要:在向參數傳遞引用類型的值時,會把這個值在內存中的地址復制給一個局部變量,因此這個局部變量的變化會反映在函數的外部。當在函數內部重寫時,這個變量的引用就是一個局部變量了,這個局部變量在函數執行完畢后立即銷毀。
前言:我入門學的 java這種強類型語言,剛開始學js第一感覺是挺簡單,后來發現還是too young。所以,本次就把作用域、匿名函數做一個完整總結,黑喂狗~~~
-------------------分割線----------------------
1.函數 返回值/參數返回值:::::::::::::::::::::::::
js的函數在定義時不必指定返回值,而且任何函數都可以通過return隨時返回值。
函數在執行完return之后停止并立即退出,因此return后面的代碼永遠不會執行。
function sum(num1,num2){ return num1 + num2; alert("Hello World"); //這段代碼永遠不會執行 }
參數:::::::::::::::
js函數不介意傳遞進來多少個參數,也不在乎傳遞進來的是什么參數類型。
參數在內部是由一個數組來表示的,函數接收的永遠都是這個數組,函數體內部可以通過arguments對象來訪問這個參數數組,從而可以獲取傳遞給函數的每一個參數。
如下代碼:
function howManyArgs(){ alert(arguments.length); } howManyArgs("String",45); //2 howManyArgs(); //0 howManyArgs(12); //1
從上面的代碼可以看出來,定義函數時沒有給函數指定參數名字,而調用時依然可以傳遞進去任何數量和類型的參數,因此在js函數中:命名的參數只是提供便利,但不是必須的。理解這點很重要。
不完美的重載:::::::::::::::::
既然可以用arguments.length判斷傳入參數的個數,那么js函數也可以實現不完美的重載。
如下代碼:
function doAdd(){ if(arguments.length == 1){ alert(arguments[0] + 10); } if(arguments.length == 2){ alert(arguments[0] + arguments[1]); } } doAdd(10); //20 doAdd(30,20); //50
arguments[i]和對應命名參數的關系:::::::::::::::::
看如下代碼:
function doAdd(num1,num2){ arguments[1] = 10; //重寫第二個參數 alert(arguments[0] + num2); }
arguments對象中的值會自動反映到對應的命名參數,但是讀取這兩個值不會訪問相同的內存空間,
修改命名參數并不會改變arguments中對應的值
arguments對象長度是由調用函數時傳入的參數個數決定的,不是由定義函數時的命名參數的個數決定的。
js中所有的函數都是按值傳遞的。
在向參數傳遞基本類型時,被傳遞的值會被復制給一個局部變量。
在向參數傳遞引用類型的值時,會把這個值在內存中的地址復制給一個局部變量,因此這個局部變量的變化會反映在函數的外部。
來看幾個例子:
function addTen(num){ num += 10; return num; } var count = 20; var result = addTen(count); alert(count); //20,沒有變化 alert(result); //30
count傳遞給參數num,函數內部num做了修改,但是沒有反映到count上。
function setName(obj){ obj.name = "Jack"; } var person = new Object(); setName(person); alert(person.name); //Jack
這個例子很容易讓人覺得,引用類型做為函數參數傳遞是按引用傳遞的,因為局部的修改:obj.name = "Jack",反映在了全局的作用域上:person.name,事實上并不是如此。
事實上:我們創建了一個對象,并把它保存在person變量中,然后把person當做參數傳遞到setName()函數中復制給了obj,在這個函數內部obj和person引用的是同一個對象。
再看一個例子:
function setName(obj){ obj.name = "Jack"; obj = new Object(); obj.name = "Rose"; } var person = new Object(); setName(person); alert(person.name); //Jack
這個例子中在setName()函數中,為obj重新定義了一個對象,另一行代碼為該對象定義了一個帶有不同值的name屬性。如果person傳遞給函數setName()之后是按引用傳遞的,那么對obj.name的修改就會反映到person.name上,事實上person.name依然是Jack。
當在函數內部重寫obj時,這個變量的引用就是一個局部變量了,這個局部變量在函數執行完畢后立即銷毀。
定義什么的太多了就不寫了,直接上代碼
var color = "blue"; function changeColor(){ var anotherColor = "red"; function swapColors(){ var tempColor = anotherColor; anotherColor = color; color = tempColor; //這里可以訪問 color,anotherColor 和tempColor } swapColor(); //這里可以訪問color, anotherColor } changeColor(); //這里只能訪問color
上面代碼中有三個執行環境:全局環境、changeColor()的局部、和swapColors()的局部環境。
全局環境中有一個color變量和changeColor()函數。
changeColor()的局部環境中有一個名為anotherColor的變量和一個swapColors()的函數,但是它也可以訪問全局環境中的變量color
swapColors()局部環境中有一個變量tempColor,只能在這個環境中訪問到。
無論是全局環境還是changeColor()的局部環境都無權訪問tempColor,在swapColors()內部可以訪問其他兩個環境中的所有變量,因為那兩個環境是它的父執行環境。
總結:內部環境可以通過作用域鏈訪問所有的外部環境,但外部環境不能訪問內部環境中的任何變量和函數,每個環境內部沒有這個變量或者函數時,都可以向上搜索變量和函數名,直到找到為止。
沒有塊級作用域java等語言話括號括起來的代碼塊都有自己的作用域,但是js中總有例外,看下面代碼:
if(true){ var color = "blue"; } alert(color); //blue
這里是在if語句中定義了一個變量color,和作用域函數里面定義變量的例子不同,在if語句中的變量聲明將添加到當前的執行環境中,看下面for循環的例子:
for(var i = 0; i<10; i++){ doSomething(i); } alert(i); //10
對于js,由for語句創建的變量i即使在for循環執行結束后,也依舊會存在于循環外部的執行環境。
4.匿名函數看下面例子:
window.onload = function(){ alert("Hello World"); }; var person = { callName: function(){ alert("My name is Jack"); } }; person.callName(); setTimeout( function(){alert("Hello World");}, 500);
1.首先,為load事件創建了一個函數做為事件處理程序,不會直接調用這個函數,而是在頁面加載時自動調用,所以沒必要為這個函數命名,像這樣:
function sayHello(){alert("Hello World");}; window.onload = sayHello;
2.聲明了一個匿名函數,做為person對象的一個屬性callName,可以通過該屬性來調用這個方法:
如:person.callName();
3.將匿名函數做為回調函數傳遞給另外一個函數,代碼中將匿名函數做為一個參數傳遞給window對象的setTimeout()方法,該方法將在半秒后被調用。
-------------------------------------------------------end--------------------------------------------------------
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/79711.html
摘要:前言最近在學前幾天看到兩道題剛開始看懵懵懂懂這幾天通過各種查資料慢慢的理解頓悟了對匿名函數閉包立即執行函數的理解也更深了一點在此分享給大家我的理解與總結希望能幫助大家理解因為這篇文章是我用心總結的查閱了很多的資料所以總結的比較細篇幅較長如果 前言 最近在學JS,前幾天看到兩道題,剛開始看懵懵懂懂,這幾天通過各種查資料,慢慢的理解,頓悟了,對匿名函數,閉包,立即執行函數的理解也更深了一點...
摘要:執行返回的內部函數,依然能訪問變量輸出閉包中的作用域鏈理解作用域鏈對理解閉包也很有幫助。早期的版本里采用是計數的垃圾回收機制,閉包導致內存泄露的一個原因就是這個算法的一個缺陷。 關于閉包,我翻了幾遍書,看了幾遍視頻,查了一些資料,可是還是迷迷糊糊的,干脆自己動手來個總結吧 !歡迎指正... (~ o ~)~zZ 1. 什么是閉包? 來看一些關于閉包的定義: 閉包是指有權...
摘要:閉包引起的內存泄漏總結從理論的角度將由于作用域鏈的特性中所有函數都是閉包但是從應用的角度來說只有當函數以返回值返回或者當函數以參數形式使用或者當函數中自由變量在函數外被引用時才能成為明確意義上的閉包。 文章同步到github js的閉包概念幾乎是任何面試官都會問的問題,最近把閉包這塊的概念梳理了一下,記錄成以下文章。 什么是閉包 我先列出一些官方及經典書籍等書中給出的概念,這些概念雖然...
摘要:閉包的學術定義先來參考下各大權威對閉包的學術定義百科閉包,又稱詞法閉包或函數閉包,是引用了自由變量的函數。所以,有另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。 前言 上一章講解了閉包的底層實現細節,我想大家對閉包的概念應該也有了個大概印象,但是真要用簡短的幾句話來說清楚,這還真不是件容易的事。這里我們就來總結提煉下閉包的概念,以應付那些非專人士的心血來潮。 閉包的學術...
摘要:一般來講,函數執行完畢后,局部活動對象就會被銷毀,內存中僅保存全局作用域,但是閉包的情況有所不同理解閉包的前提先理解另外兩個內容作用域鏈垃圾回收作用域鏈當代碼在執行過程中,會創建變量對象的一個作用域鏈。 閉包是javascript語言的一個難點,也是它的特色,很多高級應用都要依靠閉包來實現。個人的理解是:函數中嵌套函數。 閉包的定義及其優缺點 閉包是指有權訪問另一個函數作用域中的變量的...
閱讀 2491·2021-10-19 11:45
閱讀 2477·2021-09-30 09:56
閱讀 1441·2021-09-30 09:47
閱讀 597·2019-08-30 15:53
閱讀 1840·2019-08-30 15:44
閱讀 587·2019-08-30 12:52
閱讀 1089·2019-08-30 11:16
閱讀 1613·2019-08-29 16:36