关于js函数 形参和局部变量名相同 的问题
来源:互联网 发布:淘宝平台怎么赚钱 编辑:程序博客网 时间:2024/04/30 00:24
原文:https://segmentfault.com/q/1010000007278354?_ea=1295176
问题:
function f1(a) { console.log(a);// 10; 这里我开始觉得是undefined的 // 我以为var a=1会先把var a=undefined 放在函数的最前面 但是好像并没有 var a=1; console.log(a);// 1 console.log(arguments[0])// 1; 这里我觉得也是10}f1(10)按照f1这个打印看来 var 声明的a 好像和形参a是有联系的 但是他们不是应该没有联系吗?function f2(a) { console.log(a); //10 var a; console.log(a);//10 console.log(arguments[0])//10}f2(10)f2 里面的a好像什么事都没做
这个问题所造成的结果,主要有两个源头,一个是函数中的arguments对象,另一个是变量在函数中的提升。
函数中的arguments
对象
先看arguments
对象,它是个函数中的隐性对象,是一个类数组(array-like)的对象。它有一些特性在这里看到,实际都是很细的特性,以下几个例子来说明:
第一个例子是一般函数,只是把传入的形参(参数)输出在主控台:
function foo(a, b){ console.log(a, b); //1, 10}foo(1, 10);
a与b改为用arguments,这很正常的用法如下:
function foo(a, b){ console.log(arguments[0], arguments[1]); //1, 10}foo(1, 10);
在函数中改arguments对象中的值,对原本的a与b会不会一起更动。有。:
function foo(a, b){ arguments[0] = 9; arguments[1] = 99; console.log(a, b); //9, 99}foo(1, 10);
在函数中改a与b的值,对arguments对象中的值会不会一起更动。有。:
function foo(a, b){ a = 8; b = 88; console.log(arguments[0], arguments[1]); //8, 88}foo(1, 10);
题外话,另一个新特性是加上ES6(ES2015)的函数参数的预设值,只要用了这个特性,arguments必无法再改变形参:
function foo(a=1, b=10){ arguments[0] = 9; arguments[1] = 99; console.log(a, b); //1, 10}foo();
函数中的变数提升(Hoisting)
变数提升是只提升定义,赋值(指定值)部份不会提升。以下为简单的例子,在函数中也是同样的情况:
console.log(x); //undefined,而不是报错var x = 5;
相等于下面这样:
var x;console.log(x);x = 5;
解题
第一个函数
问题的第一例的代码是像下面这样,我把注解先去掉:
function f1(a) { console.log(a); var a=1; console.log(a); console.log(arguments[0]);}f1(10)
f1中首先看到的是var的变数提升,所以在执行时,第1个console.log(a)前面,应该会有var a
的定义出现,但没有赋值部份。这里可以先写出在a=1之后的console.log(a)
必然是1
,然后根据上面关于arguments对象的测试结果,最后一个也是输出1
function f1(a) { var a; console.log(a); a=1; console.log(a); //1 console.log(arguments[0]); //1}f1(10)
另一个问题来了,a以10传入时,遇到一个var a
,会变为undefined
吗?先说结论,结论是"不会"。
在js中对于变量的宣告,是对剖析器的指示(directive),而不是在执行期的命令(command),不要忘了js是个直译式的脚本语言,所有的真实执行,是由js引擎中的剖析器(或分析器),先对代码作整理剖析完了,才会执行。有个最明显的特性是变量的类型是动态的,要看赋给变量什么值,才会决定这个变量的类型,你给变量一个数字,变量就变为数字类型,给它个字串,它就是个字串类型。
那么,像这里的重覆宣告,js又是怎么认为的?看下面的例子:
//第一例var a = 10;var a;console.log(a); //10//第二例var b = 10;var b = undefined;console.log(b); //undefined
js在执行时会对相同变量宣告作归纳的处理,以最近的变量指定作为变量在执行时的值。以第一例来说,第二行的var a
只是个宣告,而不是赋值,除非在执行前的语句,都没有对a变量赋值的其他语句,a才会被js引擎当作undefined值,也就是"不知道是什么东西,没定义"。第二例则是直接赋给b变量个undefined
,js引擎当然是就认为b是个undefined
类型。
所以,以本问题的在函数中的第一个console.log(a);
来说,它a的值是10
,而不是你认为的undefined
。
第二个函数
function f2(a) { console.log(a); var a; console.log(a); console.log(arguments[0])}f2(10)
这个函数也一样有变量提升,所以相当于下面的代码:
function f2(a) { var a; console.log(a); console.log(a); console.log(arguments[0])}f2(10)
依照第一个函数的最后说明,变量宣告var a
被合并(归纳)掉,所以全部的console.log都是打印出10
,收工。
风格建议
这个例子可以看出几个建议的撰写风格。
第1: 变量的宣告都要在函数的最上面,提高可阅读性以避免在执行语句中间宣告。
第2: 不要重覆宣告变量,尤其常见是在for语句中。用var宣告的变量作用域是以函数为分界,而不是区域语句(for、if…)。
第2: 不要在函数的区块中间,宣告与形参同名的变量。除非你很确定在这是什么与在作什么,形参预设值自然有预设值的写法。
第3: 不要再用arguments
对象,它的行为是怪异的,而且设计有问题,又是"隐性"对象。与其你花时间研究它,不如把时间花在学其馀参数写法。arguments
对象是js中有名的坏设计,连js的发明者都自己说了,参考:https://brendaneich.com/2011/...
- 关于js函数 形参和局部变量名相同 的问题
- js函数中的局部变量和形参的冲突问题
- 关于函数返回局部变量的问题
- 关于栈和局部变量的问题
- js中的变量名和函数名重名问题
- JS变量名和函数名的提升
- 关于JS里的全局变量和局部变量
- js 中局部变量和全局变量输出遇到的问题
- JS中最经典的全局变量和局部变量问题
- JS中最经典的全局变量和局部变量问题
- JS中最经典的全局变量和局部变量问题
- JS中最经典的全局变量和局部变量问题
- 关于自定义类型名和函数名相同
- 关于函数传参,全局变量,局部变量的一点认识
- 不一致的变量名和函数名
- 返回函数局部变量的问题
- 函数返回局部变量的一些问题
- 函数返回局部变量的问题
- POJ 2778-DNA Sequence(AC自动机+矩阵乘法)
- 在PHP中实现按照预定规则自动生成编号的方法
- java读取大文件
- Trees on the level HDU
- win10 配置TensorFlow环境
- 关于js函数 形参和局部变量名相同 的问题
- iOS开发 MFMailComposeViewController(发送邮件)的使用
- Oracle内置函数之数值型函数
- Myeclipse导入xml编写代码提示步骤(以struts2 的配置文件为例)
- 《利用Python进行数据分析》笔记---第8章绘图和可视化
- netty学习笔记(一)
- java 查询mongo模糊匹配
- Java基础巩固之梦-01.错失工作机遇之谈
- STM32 Boot模式设置方法