Maison interface Web js tutoriel javascript管中窥豹 形参与实参浅析_javascript技巧

javascript管中窥豹 形参与实参浅析_javascript技巧

May 16, 2016 pm 05:58 PM
Arguments paramètres formels

引子:
今天看到别人的一个题目:

复制代码 代码如下:

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

感觉自己对这也是一知半解,自己也可以试一下,于是就特地分析一下。
本想从语言的角度来分析,无奈功力不够,只能粗浅的尝试一下,于是称之管中窥豹,还望大牛指正。
这是昨天写的,今天吃饭的时候又想了一下,想来想去感觉有些问题还是说得不靠谱,于是又试着修改了一下。
每一本js入门书籍都会提到,JS的函数内部有一个Arguments的对象arguments,用来函数调用的时候实际传入函数的参数,fn.length保存形参的长度。
这些对分析来说略有用处,可是我想得到更多形参的信息,不知道有谁有比较好的办法,我暂时无解。
于是只能模拟了。
先不理会模拟,从实际问题出发:
复制代码 代码如下:

BR>"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">







重点关注后面两个函数(fn_1,fn_2)的执行,在这里,我们直接重新声明了形参对应的x,看到网上有的人说这是声明的一个局部变量x。
也是,不过这个局部变量不是一般的局部变量,x直接关联对应的arguments,上面的实例中就是x关联arguments[0];
所以我猜测这个赋值的流程应该是
1、函数定义的时候,声明了形参,如果函数体内有相同名称的局部变量,则忽略此声明。同时函数体内同时会有一个对象arguments;
(乱入一句:个人以为arguments当初不定义成数组的一个考虑是否是因为在函数定义内无法确定实际参数的个数[运行时动态确定],那么要么这个数组无限大,要么数组一取值就越界)。
回到正题:
对于fn_2,初始化形参相当于var x;(此时x没有赋值,默认为undefined,赋值是在语句执行的时候赋值的)
所以如果可以这么写的话,fn_2就应该是这样:
复制代码 代码如下:

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

2、函数语法检测通过,执行的时候,函数内部的arguments对象一开始就得到赋值,赋值完毕后,函数体内的语句开始执行。
下面的一段表述是我自己想的,不知道正确不正确(特别是关联的说法):
复制代码 代码如下:

一旦发现形参(对应的变量)被赋值,那么会去寻找arguments对应的项,如果发现了arguments对应的项,那么设置形参与arguments对应项的关联。如果没有发现arguments里面对应的项(undefined),那么形参和arguments还是保持独立。这里寻找的是arguments在函数运行开始的一个快照。反过来arguments赋值也是一样。

上面的删除的部分是昨天的,红字部分是写到一半的时候发现有问题加上去的。今天回过神来,昨天为什么要傻逼的想到快照呢,这个不就是函数开始运行时直接
判断关联么?于是改了一下表述:
复制代码 代码如下:

在函数开始执行时,设置形参与arguments的关联信息。如果形参与对应的arguments里面能找到对应的项(均为undefined),那么两者关联。后面不论怎么处理,都不会改变整个函数体内的关联信息。

于是后面的实例说明的说法也要改变:
回到例子,fn_2函数语法检测通过,从第二步开始执行:
不带参数的情况
复制代码 代码如下:

fn_2();
function fn_2(x){//arguments赋值完成,由于没有实参,于是arguments参数列表为空。同时判断关联信息,显然形参有,arguments空,两者相互独立,以后都不会再关联
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
}

带参数的情况
复制代码 代码如下:

带参数的情况 fn_2(1);
function fn_2(x){//arguments赋值完成,arguments[0]=1。同时形参x有值,两者相关联,永结同心。
var x = 3;//x赋值为3,x与arguments[0]关联,于是arguments[0]被赋值为3,。
console.log(x,arguments[0]);//打印x=3,arguments[0] = 3
arguments[0] = 2;//arguments[0]被赋值2,由于x与arguments[0]已经关联到一起,于是x同时改变
console.log(x,arguments[0]);//打印x = 2,arguments[0]=2
}

反过来应该也是一样的:
不带参数
复制代码 代码如下:

fn_2();
function fn_2(x){//不关联
arguments[0] = 2;//找不到对应的x(undefined),相互独立
console.log(x,arguments[0]);//undefined,2
x = 3;//相互独立,快照。虽然arguments动态添加了,老死不相往来,所以依旧失败
console.log(x,arguments[0]);//3,2
}

带参数
复制代码 代码如下:

fn_2(1);
function fn_2(x){
arguments[0] = 2;//关联
console.log(x,arguments[0]);//2,2
x = 3;//关联
console.log(x,arguments[0]);//3,3
}

由于我们只有一个形参,可能说服力不够,现在增加到两个。
只有一个实参的情况:
复制代码 代码如下:

fn_2(1);
function fn_2(x,y){ //arguments赋值完成,arguments[0]=1,arguments[1]=undefined,因此只有x与arguments[0]关联,y与arguments[1]老死不往来
console.log(x,y,arguments[0],arguments[1]); //1,undefined,1,undefined
var x = 3; //x赋值为3,x与arguments[0]关联,于是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]已经关联到一起,于是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
}

有两个实参的情况:
复制代码 代码如下:

fn_3(1,6);
function fn_3(x,y){ //arguments赋值完成,arguments[0]=1,arguments[1]=6,x与arguments[0],y与arguments[1]都相互关联
console.log(x,y,arguments[0],arguments[1]); //1,6,1,6
var x = 3; //x赋值为3,x与arguments[0]关联,于是arguments[0]被赋值为3。
console.log(x,y,arguments[0],arguments[1]); //3,6,3,6
var y = 4; //y赋值为3,y与arguments[1]关联,于是arguments[1]被赋值为4。
console.log(x,y,arguments[0],arguments[1]); //3,4,3,4
arguments[0] = 2; //arguments[0]被赋值2,由于x与arguments[0]已经关联到一起,于是x同时改变
console.log(x,y,arguments[0],arguments[1]); //2,4,2,4
arguments[1] = 5; //arguments[1]被赋值5,由于y与arguments[1]已经关联到一起,于是y同时改变
console.log(x,y,arguments[0],arguments[1]); //x=2,y=5,arguments[0]=2,arguments[1]=5
}

以上全部是推测,因为实际中没有办法形参的信息,所以我按照推测写了一个小测试:
下面的也改了:
复制代码 代码如下:

function _Function(){//获得的形参列表为数组:_args
var _args = [];
for(var i = 0; 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实现为一个数组,而非arguments对象
this.exec = function(){
//函数运行时,实参_arguments被赋值
var _arguments = [];
for(var i = 0; i _arguments[i] = arguments[i];
}
//下面执行函数体
eval(fn_body);
}
}

替换成:
复制代码 代码如下:

function _Function(){//获得的形参列表为数组:_args
var _args = [];
for(var i = 0; 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实现为一个数组,而非arguments对象
this.exec = function(){
//函数运行时,实参_arguments被赋值
var _arguments = [];
for(var i = 0; i _arguments[i] = arguments[i];
}
//在运行开始就判断关联信息
for(var j = 0; j _args[j]["link"] = true;
}
//下面执行函数体
eval(fn_body);
}
}

上面按理来说,关联应该是把两者指向同一个对象,可是我只需要分析例子,没打算做得那么精细,所以是在函数体里面用if语句判断的 。
把例子中fn_2换成对应的形式就是:
复制代码 代码如下:

// 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;来表示形参与实参相关联
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);

画了一张图来表示实例与改写函数两者的关系,顺便也改了一下:

回到文章开头的例子:
复制代码 代码如下:

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

显然,两者相互独立:
x = 10,arguments[0] = 20;
推测一下:
复制代码 代码如下:

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

应该都是输出20,20
复制代码 代码如下:

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

应该也都是输出20,20
复制代码 代码如下:

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

应该是undefined和20
原文来自cnblogs小西山子
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Où trouver la courte de la grue à atomide atomique
1 Il y a quelques semaines By DDD

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Remplacer les caractères de chaîne en javascript Remplacer les caractères de chaîne en javascript Mar 11, 2025 am 12:07 AM

Explication détaillée de la méthode de remplacement de la chaîne JavaScript et de la FAQ Cet article explorera deux façons de remplacer les caractères de chaîne dans JavaScript: le code JavaScript interne et le HTML interne pour les pages Web. Remplacer la chaîne dans le code JavaScript Le moyen le plus direct consiste à utiliser la méthode Remplace (): str = str.replace ("trouver", "remplacer"); Cette méthode remplace uniquement la première correspondance. Pour remplacer toutes les correspondances, utilisez une expression régulière et ajoutez le drapeau global G: str = str.replace (/ fi

Créez vos propres applications Web Ajax Créez vos propres applications Web Ajax Mar 09, 2025 am 12:11 AM

Vous voici donc, prêt à tout savoir sur cette chose appelée Ajax. Mais qu'est-ce que c'est exactement? Le terme Ajax fait référence à un regroupement lâche de technologies utilisées pour créer un contenu Web interactif dynamique. Le terme Ajax, inventé à l'origine par Jesse J

Comment créer et publier mes propres bibliothèques JavaScript? Comment créer et publier mes propres bibliothèques JavaScript? Mar 18, 2025 pm 03:12 PM

L'article discute de la création, de la publication et du maintien des bibliothèques JavaScript, en se concentrant sur la planification, le développement, les tests, la documentation et les stratégies de promotion.

Comment optimiser le code JavaScript pour les performances dans le navigateur? Comment optimiser le code JavaScript pour les performances dans le navigateur? Mar 18, 2025 pm 03:14 PM

L'article traite des stratégies pour optimiser les performances JavaScript dans les navigateurs, en nous concentrant sur la réduction du temps d'exécution et la minimisation de l'impact sur la vitesse de chargement de la page.

Effets de la matrice jQuery Effets de la matrice jQuery Mar 10, 2025 am 12:52 AM

Apportez des effets de film de matrice à votre page! Ceci est un plugin jQuery cool basé sur le célèbre film "The Matrix". Le plugin simule les effets de caractère vert classique dans le film, et sélectionnez simplement une image et le plugin le convertira en une image de style matrice remplie de caractères numériques. Venez et essayez, c'est très intéressant! Comment ça marche Le plugin charge l'image sur la toile et lit le pixel et les valeurs de couleur: data = ctx.getImagedata (x, y, settings.grainsize, settings.grainsize) .data Le plugin lit intelligemment la zone rectangulaire de l'image et utilise jQuery pour calculer la couleur moyenne de chaque zone. Ensuite, utilisez

Comment déboguer efficacement le code JavaScript à l'aide d'outils de développeur de navigateur? Comment déboguer efficacement le code JavaScript à l'aide d'outils de développeur de navigateur? Mar 18, 2025 pm 03:16 PM

L'article traite du débogage efficace de JavaScript à l'aide d'outils de développeur de navigateur, de se concentrer sur la définition des points d'arrêt, de l'utilisation de la console et d'analyser les performances.

Comment construire un simple curseur jQuery Comment construire un simple curseur jQuery Mar 11, 2025 am 12:19 AM

Cet article vous guidera pour créer un carrousel d'image simple à l'aide de la bibliothèque JQuery. Nous utiliserons la bibliothèque BXSLider, qui est construite sur jQuery et offre de nombreuses options de configuration pour configurer le carrousel. De nos jours, Picture Carrousel est devenue une fonctionnalité incontournable sur le site Web - une image vaut mieux que mille mots! Après avoir décidé d'utiliser le carrousel d'image, la question suivante est de savoir comment la créer. Tout d'abord, vous devez collecter des images de haute qualité et haute résolution. Ensuite, vous devez créer un carrousel d'image en utilisant HTML et un code JavaScript. Il existe de nombreuses bibliothèques sur le Web qui peuvent vous aider à créer des carrousels de différentes manières. Nous utiliserons la bibliothèque BXSLider open source. La bibliothèque Bxslider prend en charge la conception réactive, de sorte que le carrousel construit avec cette bibliothèque peut être adapté à n'importe quel

Comment télécharger et télécharger des fichiers CSV avec Angular Comment télécharger et télécharger des fichiers CSV avec Angular Mar 10, 2025 am 01:01 AM

Les ensembles de données sont extrêmement essentiels pour créer des modèles d'API et divers processus métier. C'est pourquoi l'importation et l'exportation de CSV sont une fonctionnalité souvent nécessaire. Dans ce tutoriel, vous apprendrez à télécharger et à importer un fichier CSV dans un

See all articles