JS在函数中形参和局部变量同名的问题

前言

上次牛客网做到这样一个题,非常有意思,陷阱非常多,当时觉得搞明白了,现在再看到,又糊涂了,发现了新的点,看一下:

var foo={n:1};

(function (foo) {
    console.log(foo.n);
    foo.n = 3;
    var foo = {n:2};
    console.log(foo.n);
})(foo);

console.log(foo.n);

乍一看,是局部和全局变量的一些区分问题,其实坑很多,下面我们一点点分析下;

变量的定义(宣告)和赋值

首先我们看一段代码:

var a = 1;
var a;
console.log(a);//1

这里第二行对a是一个重复宣告,而不是赋值,变量只有定义(宣告)后未赋值的情况下才会输出undefined,除非手动赋值undefined;那么这里,JS引擎对于重复宣告的规定以最近的变量指定(也就是赋值)作为变量在执行时的值,所以第二行的var a;其实相当于无效;

函数中形参和局部变量同名

在我们自己写代码时,一般不会做这种蠢事情,把形参和局部变量定义为同名,可如果真的这样做了呢?
那就要分析下JS执行上下文中的变量对象了,这个知识点不牢固的同学可以移步这里:重拾ECMAScript基础——变量、作用域
作用域链对变量的保存都是在变量对象中的,那么ES5对形参在变量对象中是如何保存的呢,请看规范:

10.5 Declaration Binding Instantiation
Every execution context has an associated VariableEnvironment. Variables and functions declared in ECMAScript code evaluated in an execution context are added as bindings in that VariableEnvironment‘s Environment Record. For function code, parameters are also added as bindings to that Environment Record.

就是说,无论是形参还是函数中声明的变量,JS对他们的处理是没有区别的,都是保存在这个函数的变量对象中作为局部变量进行处理;那么结合上面我们说到的变量的重复宣告,接下来同名的问题就很简单了,看代码:

(function fun (param) {
    var param;
    console.log(param);//1
    param = 2;
    console.log(param);//2
})(1);

在这里,同名的局部变量和形参其实是同一个东西,都是在函数的变量对象里的保存的那个变量;

如果变量是引用类型呢?

那么如果变量是个对象的话,就是我们文章一开始提到的题目了,下面我们分析下:

var foo = {n : 1};
(function(foo) {
    console.log(foo.n);
    foo.n = 3;
    var foo = {n : 2};
    console.log(foo.n);
})(foo);
console.log(foo.n);

var foo = {n : 1};
function fun(foo) {
    var foo;
    console.log(foo.n);
    foo.n = 3;
    foo = {n : 2};
    console.log(foo.n);
};
fun(foo);
console.log(foo.n);

上下两段代码,意思是一样的,我把匿名立即执行函数换成了普通函数并在下一行调用,方便大家理解;

其实分析一下,就是这么几个问题;
内部foo变量提升;
内部foo和形参同名;
内部foo重复宣告;
所以内部var的那个foo和形参foo是同一个东西,并没有发生变化;
然后重复宣告不影响之前的赋值,所以第一个为1;
接下来,foo.n=3,由于形参为对象,所以是传进来的是一个对象的引用(指针);
对这块知识点不牢固的同学还是请移步我之前那篇文章;
那么这个引用指向的堆内存的那块空间里的n改变为3;
接下来,foo={n:2};这个就很有意思了,我们刚才也说了,传进来的是个引用;
现在给这个引用赋值,实际上就是让它指向新开辟的空间,存放着{n:2}这个对象;
那么之前的引用就断掉了,也就是说形参foo已经不指向全局里那个foo指向的空间了;
固然,在函数里,会输出新空间里的2;
而在函数外,旧空间仍然没有改变,故为3;

总结

其实这个题目考了很多知识点,最后就是参数传递中引用类型的用法,这个也是ECMAScript中基础的一个难点,结合前面的一些,变量提升,重复宣告,形参与局部变量同名,算是解释清楚了。

若有错误,欢迎指出。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容

  • __block和__weak修饰符的区别其实是挺明显的:1.__block不管是ARC还是MRC模式下都可以使用,...
    LZM轮回阅读 3,297评论 0 6
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,513评论 1 51
  • ———————————————回答好下面的足够了---------------------------------...
    恒爱DE问候阅读 1,713评论 0 4
  • 在js中,函数本身属于对象的一种,因此可以定义、赋值,作为对象的属性或者成为其他函数的参数。函数名只是函数这个对象...
    bjhu电net阅读 528评论 0 5
  • 新年越发的近了 我回头望了望自己过去的路 有坎坷、有艰辛 有鲜花掌声,也有跌宕起伏 但是,我都挺过了 每个脚印里都...
    萧娜阅读 411评论 5 6