JavaScript 基础函数_深入剖析变量和作用域


Posted in Javascript onMay 18, 2016

函数定义和调用

定义函数,在JavaScript中,定义函数的方式如下:

function abs(x){ 
if(x >=0){ 
return x;
}else{ 
return -x;
}
}

上述abs() 函数的定义如下:

function 指出这是一个函数定义;

abs 是函数的名称;

(x) 括号内列出函数的参数,多个参数以,分隔;

{...}之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。

注意:函数体内部的语句在执行时,一旦执行到return 时,函数就执行完毕,并将结果返回。因此内部通过条件判断和循环可以在实现非常复杂的。

如果没有return语句,函数执行完毕后也会返回结果,只是结果为undefined。

由于JavaScript的函数也是一个对象,上述定义的abs()函数实际上是一个函数对象,而函数名abs可以视为指向该函数的变量。

var abs = function(x){ 
if(x >= 0){ 
return x;
} else { 
return -x;
}
}

在这种方式下,function (x) { ... }是一个匿名函数,它没有函数名。但是,这个匿名函数赋值给了变量abs,所以,通过变量abs就可以调用该函数。

两种定义完全等价,注意第二种方式按照完整语法需要在函数体末尾加一个;,表示赋值语句结束。

调用函数时,按顺序传入参数即可:

abs(10); // 返回10
abs(-9); // 返回9

由于JavaScript 允许传入任意个参数而不受影响调用,因此传入的参数比定义的参数多也没有问题,虽然函数内部并不需要这些参数。

abs(10,'blablabla'); //返回10
abs(-9,'haha','hehe',null) // 返回9

传入的参数比定义的少也没有问题

abs(); 返回NaN

此时abs(x)函数的参数x 将收到undefined,计算结果为NaN

function abs(x){ 
if(typeof x !=='number'){ 
throw 'Not a number':
}
 if(x >=0){ 
return x;
}else{ 
return -x;
}
}

arguments

JavaScript 还有一个免费赠送的关键字 arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。

function foo(x){ 
alert(x); // 10
for(var i=0; i < arguments.length;++){ 
alert(arguments[i]); // 10,20,30
}
}
foo(10.20,30)

利用arguments,你可以获得调用者传入的所有参数。也就是说,即使函数不定义任何参数,还是可以拿到参数的值:

function abs(){ 
if(arguments.length ===0){ 
return 0;
}
var x = arguments[0]
return x >=0 ? x : -x;
}
abs(); //0
abs(10); // 10
abs(-9) //9

实际上arguments最常用于判断传入参数的个数。你可能会看到这样的写法:

// foo(a[,b],c)

//接受2~3 个参数,b 是可选参数,如果只要出入两个参数,b默认为null

function foo(a,b,c){ 
if(arguments.length ===2){ 
// 实际拿到的参数是a 和b c 为undefined
c = b;
b = null; // b 变为默认值

要把中间的参数b变为“可选”参数,就只能通过arguments判断,然后重新调整参数并赋值。

rest 参数

由于JavaScript 函数允许接收任意个参数,遇事我们就不得不用arguments 来获取所有的参数:

function foo(a,b){ 
var i, rest = [];
if(arguments.length > 2){ 
for(i = 2; i < arguments.length; i++){ 
rest.push(arguments[i]);
}
}
console.log('a =' + a);
console.log('b = ' + b);
console.log(rest);
}

为了获取除了已定义参数a、b之外的参数,我们不得不用arguments,并且循环要从索引2开始以便排除前两个参数,这种写法很别扭,只是为了获得额外的rest参数,有没      有更好的方法?

ES6标准引入了rest参数,上面的函数可以改写为:

function foo(a,b,...rest){ 
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}
foo(1,2,3,4,5);
//结果
// a = 1
// b = 2
// Array[3,4,5]
foo(1)
// 结果
// a = 1
// b = undefined
// Array []

rest 参数只能写在最后,前面用... 标示,从运行结果可知,传入的参数先绑定 a , b, 多余的参数以数组形式交给变量 rest,所以,

不在需要 arguments 我们就获取了全部参数。

如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined)。

return 语句

前面我们讲到了JavaScript引擎有一个在行末自动添加分号的机制,这可能让你栽到return语句的一个大坑:、

function foo(){ 
return {name:'foo'};
}
foo(); // {name:'foo'}

要注意:

function foo(){ 
return: //自动添加了分号,相当于return undefined
{name:'foo'}; // 这行语句已经没法执行到了。
}

所以正确的多行写法是

function foo(){ 
return { // 这里不会自动加分号,因为表示语句尚未结束。
name:'foo'
}
}

变量作用域

在JavaScript 中,用var 声明的实际上是有作用域的。

如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不该引用该变量。

‘use strict':
function foo(){ 
var x = 1;
x = x +1;
}
x = x +2; // RefrenceError 无法在函数体外引用该该变量x

如果两个不同的函数各自申明了同一个变量,那么该变量只在各自的函数体内起作用。换句话说,不同函数内部的同名变量互相独立,互不影响:

'use struct':
function foo(){ 
var x = 1;
x = x +1;
}
function bar (){ 
var x= 'A';
x = x + 'B';
}

由于JavaScript的函数可以嵌套,此时,内部函数可以访问外部函数定义的变量,反过来则不行:

'use strict';
function foo(){ 
var x =1;
function bar(){ 
var x = 1;
function bar(){ 
var y= x +1; //bar 可以访问foo 的变量x
}
var z = y + 1; //RefernceError! foo 不可以访问bar 的变量y!
}
}

如果内部函数和外部函数的变量名重名怎么办?

'use strict':
function foo(){ 
var x = 1;
function bar (){ 
var x = 'A';
alert('x in bar() =' + x); // 'A'
}
alert('x in foo()=' +x) //1
bar();
}

变量提升

JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:

'use strict';
function foo(){ 
var x='Hello,'+y;
alert(x);
var y = 'Bob';
}
foo();

对于上述foo()函数,JavaScript引擎看到的代码相当于:

function foo(){ 
var y; // 提升变量y的
var x = 'Hello' + y;
alert(x);
y = 'Bob';
}

由于JavaScript的这一怪异的“特性”,我们在函数内部定义变量时,请严格遵守“在函数内部首先申明所有变量”这一规则。最常见的做法是用一个var申明函数内部用到的所有变量:

function foo(){ 
var x =1, // x 初始化为1
y = x +1, // y 初始化为2
z,i; // z和i 为undefined
// 其他语句
for(i =0; i<100; i++){ 
...
}
}

全局作用域

不在任何函数内定义的变量就具有全局作用域,实际上,JavaScript 默认有一个全局作用域的变量实际上呗绑定到window 的一个属性。

‘use strict';
var sourse = 'Learn JavaScript';
alert(course); // 'Learn JavaScript';
alert(window.course); // 'Learn JavaScript'

名字空间

全局变量会绑定到window 上,不同的JavaScript 文件如果使用相同的全局变量,或者定义了相同名字的顶层函数,都会造成

命名冲突,并且很难被发现,

减少冲突的一个方法是把自己的所有的变量和函数全部绑定到一个全局变量中。

// 唯一的曲剧变量MYAPP
var MYAPP = {};
//其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;

// 其他函数
MYAPP.foo = function (){ 
return 'foo';
};

把自己的代码全部放入唯一的名字空间MYAPP中,会大大减少全局变量冲突的可能。

局部作用域

由于JavaScript 的变量作用域实际上是函数内部,我们在for 循环等语句块中是无法定义具有无法定义具有局部作用域的变量的。

function foo(){ 
for(var i = 0; i<100; i++){ 
//
}
i+=100; // 仍然可以引用变量;
}

为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量:

function foo(){ 
var sum = 0;
for(let i=0; i<100;i++){ 
sum +=i;
}
i +=1;
}

常量

由于var 和let 声明的变量,如果要声明一个常量,在ES6 之前是不行的,我们通常用全部大写的变量俩表示这是一个常量

不要修改他的值。

var PI = 3.14;
ES6标准引入了新的关键字const 来定义常量,const 与 let都具有块级作用域;
const PI = 3.14;
PI = 3; // 某些浏览器不报错,但是无效果。
PI; // 3.14

以上这篇JavaScript 基础函数_深入剖析变量和作用域就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Javascript 获取字符串字节数的多种方法
Jun 02 Javascript
Extjs 几个方法的讨论
Jan 28 Javascript
使用js简单实现了tree树菜单
Nov 20 Javascript
asm.js使用示例代码
Nov 28 Javascript
express的中间件cookieParser详解
Dec 04 Javascript
JavaScript面向对象分层思维全面解析
Nov 22 Javascript
简单实现AngularJS轮播图效果
Apr 10 Javascript
基于JavaScript实现多级菜单效果
Jul 25 Javascript
JavaScript检查数据中是否存在相同的元素(两种方法)
Oct 07 Javascript
详解JavaScript中的函数、对象
Apr 01 Javascript
vue-froala-wysiwyg 富文本编辑器功能
Sep 19 Javascript
Vue 集成 PDF.js 实现 PDF 预览和添加水印的步骤
Jan 22 Vue.js
实现JavaScript的组成----BOM和DOM详解
May 18 #Javascript
深入理解JQuery中的事件与动画
May 18 #Javascript
Adapter适配器模式在JavaScript设计模式编程中的运用分析
May 18 #Javascript
jQuery添加options点击事件并传值实例代码
May 18 #Javascript
详解JavaScript实现设计模式中的适配器模式的方法
May 18 #Javascript
深入剖析javascript中的exec与match方法
May 18 #Javascript
JQuery中attr属性和jQuery.data()学习笔记【必看】
May 18 #Javascript
You might like
天使彦史上最神还原,性别曝光的那一刻,百万网友恋爱了
2020/03/02 国漫
php连接mssql的一些相关经验及注意事项
2013/02/05 PHP
CentOS下PHP7的编译安装及MySQL的支持和一些常见问题的解决办法
2015/12/17 PHP
PHP版本的选择5.2.17 5.3.27 5.3.28 5.4 5.5兼容性问题分析
2016/04/04 PHP
php实现微信模拟登陆、获取用户列表及群发消息功能示例
2017/06/28 PHP
PHP守护进程化在C和PHP环境下的实现
2017/11/21 PHP
node.js中的events.emitter.listeners方法使用说明
2014/12/10 Javascript
JavaScript中String.prototype用法实例
2015/05/20 Javascript
jQuery实现带动画效果的多级下拉菜单代码
2015/09/08 Javascript
canvas实现图像布局填充功能
2017/02/06 Javascript
详解前后端分离之VueJS前端
2017/05/24 Javascript
详解用vue编写弹出框组件
2017/07/04 Javascript
详解JavaScript 作用域
2020/07/14 Javascript
原生js canvas实现鼠标跟随效果
2020/08/02 Javascript
Antd表格滚动 宽度自适应 不换行的实例
2020/10/27 Javascript
python paramiko实现ssh远程访问的方法
2013/12/03 Python
videocapture库制作python视频高速传输程序
2013/12/23 Python
Python Queue模块详解
2014/11/30 Python
python中字符串前面加r的作用
2015/06/04 Python
深入学习Python中的装饰器使用
2016/06/20 Python
python-itchat 获取微信群用户信息的实例
2019/02/21 Python
django云端留言板实例详解
2019/07/22 Python
Keras loss函数剖析
2020/07/06 Python
Python实现微信表情包炸群功能
2021/01/28 Python
大学毕业生通用求职信
2013/09/28 职场文书
技术总监的工作职责
2013/11/13 职场文书
家居设计专业个人自荐信范文
2013/11/26 职场文书
甜品蛋糕店创业计划书范文
2014/02/06 职场文书
本科毕业自我鉴定
2014/03/20 职场文书
法定代表人身份证明书
2014/09/10 职场文书
2014党支部对照检查材料思想汇报
2014/10/05 职场文书
四风批评与自我批评发言稿
2014/10/14 职场文书
父亲节活动总结
2015/02/12 职场文书
运动会开幕式通讯稿
2015/07/18 职场文书
python 下划线的多种应用场景总结
2021/05/12 Python
Nginx 匹配方式
2022/05/15 Servers