亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

javascript管中窺豹 形參與實參淺析

 更新時間:2011年12月17日 23:47:18   作者:  
本想從語言的角度來分析,無奈功力不夠,只能粗淺的嘗試一下,于是稱之管中窺豹,還望大牛指正
引子:
今天看到別人的一個題目:
復(fù)制代碼 代碼如下:

function fn(x){
x = 10;
arguments[0] = 20;
console.log(x,arguments[0])
}
fn()

感覺自己對這也是一知半解,自己也可以試一下,于是就特地分析一下。
本想從語言的角度來分析,無奈功力不夠,只能粗淺的嘗試一下,于是稱之管中窺豹,還望大牛指正。
這是昨天寫的,今天吃飯的時候又想了一下,想來想去感覺有些問題還是說得不靠譜,于是又試著修改了一下。
每一本js入門書籍都會提到,JS的函數(shù)內(nèi)部有一個Arguments的對象arguments,用來函數(shù)調(diào)用的時候?qū)嶋H傳入函數(shù)的參數(shù),fn.length保存形參的長度。
這些對分析來說略有用處,可是我想得到更多形參的信息,不知道有誰有比較好的辦法,我暫時無解。
于是只能模擬了。
先不理會模擬,從實際問題出發(fā):
復(fù)制代碼 代碼如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<script type="text/javascript">
//形參中含有隱形的聲明var x = undefined
function fn(x){
console.log(x,arguments[0]);
arguments[0] = 2;
console.log(x,arguments[0]);
}
console.log('fn():');
fn();
//undefined , undefined
//undefined , 2
console.log('fn(1):');
fn(1);
//1,1
//2,2

重點關(guān)注后面兩個函數(shù)(fn_1,fn_2)的執(zhí)行,在這里,我們直接重新聲明了形參對應(yīng)的x,看到網(wǎng)上有的人說這是聲明的一個局部變量x。
也是,不過這個局部變量不是一般的局部變量,x直接關(guān)聯(lián)對應(yīng)的arguments,上面的實例中就是x關(guān)聯(lián)arguments[0];
所以我猜測這個賦值的流程應(yīng)該是
1、函數(shù)定義的時候,聲明了形參,如果函數(shù)體內(nèi)有相同名稱的局部變量,則忽略此聲明。同時函數(shù)體內(nèi)同時會有一個對象arguments;
(亂入一句:個人以為arguments當(dāng)初不定義成數(shù)組的一個考慮是否是因為在函數(shù)定義內(nèi)無法確定實際參數(shù)的個數(shù)[運行時動態(tài)確定],那么要么這個數(shù)組無限大,要么數(shù)組一取值就越界)。
回到正題:
對于fn_2,初始化形參相當(dāng)于var x;(此時x沒有賦值,默認為undefined,賦值是在語句執(zhí)行的時候賦值的)
所以如果可以這么寫的話,fn_2就應(yīng)該是這樣:
復(fù)制代碼 代碼如下:

function fn_2(var x){
x = 3;
console.log(x,arguments[0]);
arguments[0] = 2;
console.log(x,arguments[0]);
}

2、函數(shù)語法檢測通過,執(zhí)行的時候,函數(shù)內(nèi)部的arguments對象一開始就得到賦值,賦值完畢后,函數(shù)體內(nèi)的語句開始執(zhí)行。
下面的一段表述是我自己想的,不知道正確不正確(特別是關(guān)聯(lián)的說法):
復(fù)制代碼 代碼如下:

一旦發(fā)現(xiàn)形參(對應(yīng)的變量)被賦值,那么會去尋找arguments對應(yīng)的項,如果發(fā)現(xiàn)了arguments對應(yīng)的項,那么設(shè)置形參與arguments對應(yīng)項的關(guān)聯(lián)。如果沒有發(fā)現(xiàn)arguments里面對應(yīng)的項(undefined),那么形參和arguments還是保持獨立。這里尋找的是arguments在函數(shù)運行開始的一個快照。反過來arguments賦值也是一樣。

上面的刪除的部分是昨天的,紅字部分是寫到一半的時候發(fā)現(xiàn)有問題加上去的。今天回過神來,昨天為什么要傻逼的想到快照呢,這個不就是函數(shù)開始運行時直接
判斷關(guān)聯(lián)么?于是改了一下表述:
復(fù)制代碼 代碼如下:

在函數(shù)開始執(zhí)行時,設(shè)置形參與arguments的關(guān)聯(lián)信息。如果形參與對應(yīng)的arguments里面能找到對應(yīng)的項(均為undefined),那么兩者關(guān)聯(lián)。后面不論怎么處理,都不會改變整個函數(shù)體內(nèi)的關(guān)聯(lián)信息。

于是后面的實例說明的說法也要改變:
回到例子,fn_2函數(shù)語法檢測通過,從第二步開始執(zhí)行:
不帶參數(shù)的情況
復(fù)制代碼 代碼如下:

fn_2();
function fn_2(x){//arguments賦值完成,由于沒有實參,于是arguments參數(shù)列表為空。同時判斷關(guān)聯(lián)信息,顯然形參有,arguments空,兩者相互獨立,以后都不會再關(guān)聯(lián)
var x = 3;//x賦值為3,x與arguments[0]相互獨立,arguments[0]還是為undefined
console.log(x,arguments[0]);//打印x=3,arguments[0]為undefined
arguments[0] = 2;//arguments被賦值,x與arguments[0]相互獨立。因此x=3不改變
console.log(x,arguments[0]);//打印x = 3,arguments[0]=2
}

帶參數(shù)的情況
復(fù)制代碼 代碼如下:

帶參數(shù)的情況 fn_2(1);
function fn_2(x){//arguments賦值完成,arguments[0]=1。同時形參x有值,兩者相關(guān)聯(lián),永結(jié)同心。
var x = 3;//x賦值為3,x與arguments[0]關(guān)聯(lián),于是arguments[0]被賦值為3,。
console.log(x,arguments[0]);//打印x=3,arguments[0] = 3
arguments[0] = 2;//arguments[0]被賦值2,由于x與arguments[0]已經(jīng)關(guān)聯(lián)到一起,于是x同時改變
console.log(x,arguments[0]);//打印x = 2,arguments[0]=2
}

反過來應(yīng)該也是一樣的:
不帶參數(shù)
復(fù)制代碼 代碼如下:

fn_2();
function fn_2(x){//不關(guān)聯(lián)
arguments[0] = 2;//找不到對應(yīng)的x(undefined),相互獨立
console.log(x,arguments[0]);//undefined,2
x = 3;//相互獨立,快照。雖然arguments動態(tài)添加了,老死不相往來,所以依舊失敗
console.log(x,arguments[0]);//3,2
}

帶參數(shù)
復(fù)制代碼 代碼如下:

fn_2(1);
function fn_2(x){
arguments[0] = 2;//關(guān)聯(lián)
console.log(x,arguments[0]);//2,2
x = 3;//關(guān)聯(lián)
console.log(x,arguments[0]);//3,3
}

由于我們只有一個形參,可能說服力不夠,現(xiàn)在增加到兩個。
只有一個實參的情況:
復(fù)制代碼 代碼如下:

fn_2(1);
function fn_2(x,y){ //arguments賦值完成,arguments[0]=1,arguments[1]=undefined,因此只有x與arguments[0]關(guān)聯(lián),y與arguments[1]老死不往來
console.log(x,y,arguments[0],arguments[1]); //1,undefined,1,undefined
var x = 3; //x賦值為3,x與arguments[0]關(guān)聯(lián),于是arguments[0]被賦值為3。
console.log(x,y,arguments[0],arguments[1]); //3,undefined,3,undefined
var y = 4; //y賦值為3,y與arguments[1]相互獨立,arguments[1]還是為undefined
console.log(x,y,arguments[0],arguments[1]); //3,4,3,undefined
arguments[0] = 2; //arguments[0]被賦值2,由于x與arguments[0]已經(jīng)關(guān)聯(lián)到一起,于是x同時改變
console.log(x,y,arguments[0],arguments[1]); //2,4,2,undefined
arguments[1] = 5; //arguments[1]被賦值5,y與arguments[1]相互獨立,于是y還是保持為4
console.log(x,y,arguments[0],arguments[1]); //x=2,y=4,arguments[0]=2,arguments[1]=5
}

有兩個實參的情況:
復(fù)制代碼 代碼如下:

fn_3(1,6);
function fn_3(x,y){ //arguments賦值完成,arguments[0]=1,arguments[1]=6,x與arguments[0],y與arguments[1]都相互關(guān)聯(lián)
console.log(x,y,arguments[0],arguments[1]); //1,6,1,6
var x = 3; //x賦值為3,x與arguments[0]關(guān)聯(lián),于是arguments[0]被賦值為3。
console.log(x,y,arguments[0],arguments[1]); //3,6,3,6
var y = 4; //y賦值為3,y與arguments[1]關(guān)聯(lián),于是arguments[1]被賦值為4。
console.log(x,y,arguments[0],arguments[1]); //3,4,3,4
arguments[0] = 2; //arguments[0]被賦值2,由于x與arguments[0]已經(jīng)關(guān)聯(lián)到一起,于是x同時改變
console.log(x,y,arguments[0],arguments[1]); //2,4,2,4
arguments[1] = 5; //arguments[1]被賦值5,由于y與arguments[1]已經(jīng)關(guān)聯(lián)到一起,于是y同時改變
console.log(x,y,arguments[0],arguments[1]); //x=2,y=5,arguments[0]=2,arguments[1]=5
}

以上全部是推測,因為實際中沒有辦法形參的信息,所以我按照推測寫了一個小測試:
下面的也改了:
復(fù)制代碼 代碼如下:

function _Function(){//獲得的形參列表為數(shù)組:_args
var _args = [];
for(var i = 0; i < arguments.length - 1; i++){
var obj = {};
obj['key'] = arguments[i];
obj[arguments[i]] = undefined;
_args.push(obj);
}
//this._argu = _args;
var fn_body = arguments[arguments.length - 1];
//下面的方法獲取實參_arguments,這里_arguments實現(xiàn)為一個數(shù)組,而非arguments對象
this.exec = function(){
//函數(shù)運行時,實參_arguments被賦值
var _arguments = [];
for(var i = 0; i < arguments.length; i++){
_arguments[i] = arguments[i];
}
//下面執(zhí)行函數(shù)體
eval(fn_body);
}
}

替換成:
復(fù)制代碼 代碼如下:

function _Function(){//獲得的形參列表為數(shù)組:_args
var _args = [];
for(var i = 0; i < arguments.length - 1; i++){
var obj = {};
obj['key'] = arguments[i];
obj[arguments[i]] = undefined;
_args.push(obj);
}
//this._argu = _args;
var fn_body = arguments[arguments.length - 1];
//下面的方法獲取實參_arguments,這里_arguments實現(xiàn)為一個數(shù)組,而非arguments對象
this.exec = function(){
//函數(shù)運行時,實參_arguments被賦值
var _arguments = [];
for(var i = 0; i < arguments.length; i++){
_arguments[i] = arguments[i];
}
//在運行開始就判斷關(guān)聯(lián)信息
for(var j = 0; j < Math.min(_arguments.length,_args.length); j++){
_args[j]["link"] = true;
}
//下面執(zhí)行函數(shù)體
eval(fn_body);
}
}

上面按理來說,關(guān)聯(lián)應(yīng)該是把兩者指向同一個對象,可是我只需要分析例子,沒打算做得那么精細,所以是在函數(shù)體里面用if語句判斷的 。
把例子中fn_2換成對應(yīng)的形式就是:
復(fù)制代碼 代碼如下:

// function fn_2(x){
// var x = 3;
// console.log(x,arguments[0]);
// arguments[0] = 2;
// console.log(x,arguments[0]);
// }
// fn_2(1)
//在fn_2body中,用_args[i]["link"] = true;來表示形參與實參相關(guān)聯(lián)
var fn_2body = ''+
'_args[0][_args[0]["key"]] = 3;'+
'if(_args[0]["link"]){ _arguments[0] = _args[0][_args[0]["key"]];}' +
'console.log(_args[0][_args[0]["key"]],_arguments[0]);'+
'_arguments[0] = 2;'+
'if(_args[0]["link"]){ _args[0][_args[0]["key"]] = _arguments[0]}' +
'console.log(_args[0][_args[0]["key"]],_arguments[0]);';
var fn_2 = new _Function('x',fn_2body);
fn_2.exec(1);

畫了一張圖來表示實例與改寫函數(shù)兩者的關(guān)系,順便也改了一下:

回到文章開頭的例子:
復(fù)制代碼 代碼如下:

function fn(x){
x = 10;
arguments[0] = 20;
console.log(x,arguments[0])
}
fn()

顯然,兩者相互獨立:
x = 10,arguments[0] = 20;
推測一下:
復(fù)制代碼 代碼如下:

function fn(x){
x = 10;
arguments[0] = 20;
console.log(x,arguments[0])
}
fn(1)

應(yīng)該都是輸出20,20
復(fù)制代碼 代碼如下:

function fn(x){
arguments[0] = 20;
console.log(x,arguments[0])
}
fn(1)

應(yīng)該也都是輸出20,20
復(fù)制代碼 代碼如下:

function fn(x){
arguments[0] = 20;
console.log(x,arguments[0])
}
fn()

應(yīng)該是undefined和20
原文來自cnblogs小西山子

相關(guān)文章

  • 寫gulp遇到的ES6問題詳解

    寫gulp遇到的ES6問題詳解

    這篇文章主要給大家介紹了關(guān)于在寫gulp遇到的ES6問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12
  • Echart中國地圖更換背景圖的方法示例

    Echart中國地圖更換背景圖的方法示例

    本文主要介紹了Echart中國地圖更換背景圖的方法示例,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Javascript添加監(jiān)聽與刪除監(jiān)聽用法詳解

    Javascript添加監(jiān)聽與刪除監(jiān)聽用法詳解

    這篇文章主要介紹了Javascript添加監(jiān)聽與刪除監(jiān)聽用法,較為詳細的分析了javascript原理與用法,并補充說明了事件監(jiān)聽的兼容性問題,非常具有實用價值,需要的朋友可以參考下
    2014-12-12
  • JavaScript 布爾操作符解析  && || !

    JavaScript 布爾操作符解析 && || !

    在一門編程語言中,布爾操作符的重要性堪比相等操作符。如果沒有測試兩個值關(guān)系的能力,那么諸如if...else和循環(huán)之類的語句就不會有用武之地了。布爾操作符一共有3個: 非、與、或
    2012-08-08
  • js 獲取瀏覽器版本以此來調(diào)整CSS的樣式

    js 獲取瀏覽器版本以此來調(diào)整CSS的樣式

    判斷當(dāng)前使用的是那個瀏覽器及瀏覽器的那個版本,根據(jù)瀏覽器版本來調(diào)整CSS的樣式,下面是獲取當(dāng)前瀏覽器的代碼,需要的朋友可以參考下
    2014-06-06
  • js插件Jcrop自定義截取圖片功能

    js插件Jcrop自定義截取圖片功能

    這篇文章主要為大家詳細介紹了js插件Jcrop自定義截取圖片功能 ,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • 功能強大的Bootstrap效果展示(二)

    功能強大的Bootstrap效果展示(二)

    這篇文章主要介紹了功能強大的Bootstrap效果展示,介紹常用Bootstrap效果的使用方法,感興趣的小伙伴們可以參考一下
    2016-08-08
  • 實現(xiàn)js保留小數(shù)點后N位的代碼

    實現(xiàn)js保留小數(shù)點后N位的代碼

    最近在做項目的時候,遇到要保留小數(shù)點后N位的問題,經(jīng)過一番思索,最終完成了,這里記錄一下,下次需要直接就能拉出來用了
    2014-11-11
  • TypeScript泛型約束條件示例詳解

    TypeScript泛型約束條件示例詳解

    有了泛型之后一個函數(shù)或容器類能處理的類型一下子擴到了無限大,似乎有點失控的感覺,所以這里又產(chǎn)生了一個約束的概念,下面這篇文章主要給大家介紹了關(guān)于TypeScript泛型約束條件的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • JavaScript實現(xiàn)數(shù)字前補“0”的五種方法示例

    JavaScript實現(xiàn)數(shù)字前補“0”的五種方法示例

    這篇文章主要介紹了JavaScript實現(xiàn)數(shù)字前補“0”的五種方法,結(jié)合具體實例形式分析了javascript數(shù)字前補0的相關(guān)操作技巧,涉及javascript字符串遍歷、迭代、截取、構(gòu)造等操作,需要的朋友可以參考下
    2019-01-01

最新評論