0

0

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

php中文网

php中文网

发布时间:2016-05-16 17:58:27

|

1209人浏览过

|

来源于php中文网

原创

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

复制代码 代码如下:

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);

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

谷歌AI
谷歌AI

Google AI Tools for everyone

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

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小西山子

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python 序列化
Python 序列化

本专题整合了python序列化、反序列化相关内容,阅读专题下面的文章了解更多详细内容。

0

2026.02.02

AO3官网入口与中文阅读设置 AO3网页版使用与访问
AO3官网入口与中文阅读设置 AO3网页版使用与访问

本专题围绕 Archive of Our Own(AO3)官网入口展开,系统整理 AO3 最新可用官网地址、网页版访问方式、正确打开链接的方法,并详细讲解 AO3 中文界面设置、阅读语言切换及基础使用流程,帮助用户稳定访问 AO3 官网,高效完成中文阅读与作品浏览。

91

2026.02.02

主流快递单号查询入口 实时物流进度一站式追踪专题
主流快递单号查询入口 实时物流进度一站式追踪专题

本专题聚合极兔快递、京东快递、中通快递、圆通快递、韵达快递等主流物流平台的单号查询与运单追踪内容,重点解决单号查询、手机号查物流、官网入口直达、包裹进度实时追踪等高频问题,帮助用户快速获取最新物流状态,提升查件效率与使用体验。

27

2026.02.02

Golang WebAssembly(WASM)开发入门
Golang WebAssembly(WASM)开发入门

本专题系统讲解 Golang 在 WebAssembly(WASM)开发中的实践方法,涵盖 WASM 基础原理、Go 编译到 WASM 的流程、与 JavaScript 的交互方式、性能与体积优化,以及典型应用场景(如前端计算、跨平台模块)。帮助开发者掌握 Go 在新一代 Web 技术栈中的应用能力。

11

2026.02.02

PHP Swoole 高性能服务开发
PHP Swoole 高性能服务开发

本专题聚焦 PHP Swoole 扩展在高性能服务端开发中的应用,系统讲解协程模型、异步IO、TCP/HTTP/WebSocket服务器、进程与任务管理、常驻内存架构设计。通过实战案例,帮助开发者掌握 使用 PHP 构建高并发、低延迟服务端应用的工程化能力。

5

2026.02.02

Java JNI 与本地代码交互实战
Java JNI 与本地代码交互实战

本专题系统讲解 Java 通过 JNI 调用 C/C++ 本地代码的核心机制,涵盖 JNI 基本原理、数据类型映射、内存管理、异常处理、性能优化策略以及典型应用场景(如高性能计算、底层库封装)。通过实战示例,帮助开发者掌握 Java 与本地代码混合开发的完整流程。

5

2026.02.02

go语言 注释编码
go语言 注释编码

本专题整合了go语言注释、注释规范等等内容,阅读专题下面的文章了解更多详细内容。

62

2026.01.31

go语言 math包
go语言 math包

本专题整合了go语言math包相关内容,阅读专题下面的文章了解更多详细内容。

55

2026.01.31

go语言输入函数
go语言输入函数

本专题整合了go语言输入相关教程内容,阅读专题下面的文章了解更多详细内容。

27

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
R 教程
R 教程

共45课时 | 6万人学习

MongoDB 教程
MongoDB 教程

共17课时 | 2.5万人学习

微信小程序开发之API篇
微信小程序开发之API篇

共15课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号