JavaScript中的变量声明
在ES5中,变量声明只有var和function以及隐式声明三种,在ES6中则增加了let,const,import和class四种。
var
ES5中最原始的变量声明,用于声明变量,其实JavaScript是弱类型语言,对数据类型变量要求不太严格,所以不必声明每一个变量的类型(这就是下面说的隐式声明,当然这并不是一个好习惯),在使用变量之前先进行声明是一种好的习惯。
1.作用域
使用var声明的变量的作用域是函数作用域(在ES5时代,只有函数作用域和全局作用域两种作用域),在一个函数内用var声明的变量,则只在这个函数内有效。
function test(){var a;console.log(a);//undefined
}
console.log(a);//ReferenceError: a is not defined
2.变量声明提升
用var声明变量时,只要在一个函数作用域内,无论在什么地方声明变量,都会把变量的声明提升到函数作用域的最前头,所以无论使用变量在变量声明前还是声明后,都不会报错(当然只是声明提前,赋值并没有提前,所以如果使用在声明之前,会输出undefined,但不会报错)。
function test(){console.log(a);//undefinedvar a=3;
}
隐式声明
当没有声明,直接给变量赋值时,会隐式地给变量声明,此时这个变量作为全局变量存在。
function test(){a=3;console.log(a);//3
}
test();
console.log(a);//3
当然要注意,隐式声明的话就没有变量声明提前的功能了,所以下面的使用是会报错的。
function test(){console.log(a);//ReferenceError: a is not defineda=3;
}
function
用function声明的是函数对象,作用域与var一样,是函数作用域。
function test(){function a(){console.log('d');}a();//'d'
}
a();//ReferenceError: a is not defined
同样,function声明也有变量声明提升,下面是两个特殊的例子:
function hello1(a){console.log(a); //[Function: a]function a(){}console.log(a);//[Function: a]
}
hello1('test'); function hello2(a){console.log(a); //testvar a=3;console.log(a);//3
}
hello2('test');
这里有涉及到函数中形参的声明,我们可以将以上两个例子看成:
function hello1(a){var a='test;console.log(a); //[Function: a]function a(){}console.log(a);//[Function: a]
}
hello1('test'); function hello2(a){var a='test;console.log(a); //testvar a=3;console.log(a);//3
}
hello2('test');
可以看到函数对象的声明也提前了,但是在形参变量声明之后(形参的变量声明在所有声明之前)。
当函数对象和普通对象同时声明时,函数对象的声明提前在普通对象之后。
function test(){ console.log(a);//[Function: a]function a(){}var a;console.log(a);//[Function: a]
}
let
ES6新增的声明变量的关键字,与var类似。
当然,与var也有很大区别:
1.作用域不同
let声明的变量的作用域是块级作用域(之前的js并没有块级作用域,只有函数作用域和全局作用域),var声明的变量的作用域是函数作用域。
{let a = 10;var b = 1;
}a // ReferenceError: a is not defined.
b // 1
2.不存在变量声明提升
用var声明变量时,只要在一个函数作用域内,无论在什么地方声明变量,都会把变量的声明提升到函数作用域的最前头,所以无论使用变量在变量声明前还是声明后,都不会报错。而let不一样,与java以及其他语言一样,let声明的变量,在未声明之前变量是不存在的。(js的语法越来越向java靠拢)
console.log(a); // undefined,但是不报错。
console.log(b); // ReferenceError: b is not defined.var a = 2;
let b = 2;
注意:在使用babel时可能会遇到这样的情况:
console.log(b); //undefined
let b = 2;
babel在翻译es6时,似乎直接将let变为了var,所以运行时也有变量声明提升了,但是在Chrome下运行时是正确的。
3.暂时性死区
所谓暂时性死区,意思是,在一个块级作用域中,变量唯一存在,一旦在块级作用域中用let声明了一个变量,那么这个变量就唯一属于这个块级作用域,不受外部变量的影响,如下面所示。
无论在块中的任何地方声明了一个变量,那么在这个块级作用域中,任何使用这个名字的变量都是指这个变量,无论外部是否有其他同名的全局变量。
暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
暂时性死区的意义也是让我们标准化代码,将所有变量的声明放在作用域的最开始。
var a = 123;
{console.log(a);//ReferenceErrorlet a;
}
4.不允许重复声明
在相同的作用域内,用let声明变量时,只允许声明一遍。 (var是可以多次声明的)
// 正确
function () {var a = 10;var a = 1;
}// 报错,Duplicate declaration "a"
function () {let a = 10;var a = 1;
}// 报错,Duplicate declaration "a"
function () {let a = 10;let a = 1;
}
const
const用来声明常量,const声明的常量是不允许改变的,只读属性,这意味常量声明时必须同时赋值, 只声明不赋值,就会报错,通常常量以大写字母命名。
阮一峰大神的书里说,在严格模式下,重新给常量赋值会报错,普通模式下不报错,但是赋值无效。但是测试了一下,无论是严格还是非严格模式,都会报错。
const A = 1;
A = 3;// TypeError: "A" is read-only
const和let类似,也是支持块级作用域,不支持变量提升,有暂时性死区.
注意:如果声明的常量是一个对象,那么对于对象本身是不允许重新赋值的,但是对于对象的属性是可以赋值的。
const foo = {};
foo.prop = 123;foo.prop// 123foo = {} // TypeError: "foo" is read-only
import
ES6采用import来代替node等的require来导入模块。
import {$} from './jquery.js'
$对象就是jquery中export暴露的对象。
import命令接受一个对象(用大括号表示),里面指定要从其他模块导入的变量名。注意:大括号里面的变量名,必须与被导入模块对外接口的名称相同。
如果想为输入的变量重新取一个名字,import命令要使用as关键字,将输入的变量重命名。
import { New as $ } from './jquery.js';
注意,import命令具有提升效果,会提升到整个模块的头部,首先执行。
class
ES6引入了类的概念,有了class这个关键字,当然,类只是基于原型的面向对象模式的语法糖,为了方便理解和开发而已,类的实质还是函数对象,类中的方法和对象其实都是挂在对应的函数对象的prototype属性下。
我们定义一个类:
//定义类
class Person {constructor(name, age) {this.name = name;this.age = age;} setSex(_sex) {this.sex=_sex;}
}
constructor方法,就是构造方法,也就是ES5时代函数对象的主体,而this关键字则代表实例对象,将上述类改写成ES5格式就是:
function Person(name, age){this.name = name;this.age = age;
}Person.prototype. setSex = function (_sex) {this.sex=_sex;
}
所以说,类不算什么新玩意,大多数类的特性都可以通过之前的函数对象与原型来推导。
1.所有类都有constructor函数,如果没有显式定义,一个空的constructor方法会被默认添加(有点类似java了)。当然所有函数对象都必须有个主体。
2.生成类的实例对象的写法,与ES5通过构造函数生成对象完全一样,也是使用new命令。
class B {}
let b = new B();
3.在类的实例上面调用方法,其实就是调用原型上的方法,因为类上的方法其实都是添加在原型上。
b.constructor === B.prototype.constructor // true
4.与函数对象一样,Class也可以使用表达式的形式定义。
let Person = class Me {getClassName() {return Me.name;}
};
相当于
var Person = function test(){}
5.Class其实就是一个function,但是有一点不同,Class不存在变量提升,也就是说Class声明定义必须在使用之前。
全局变量
全局对象是最顶层的对象,在浏览器环境指的是window对象,在Node.js指的是global对象。
ES5之中,全局对象的属性与全局变量是等价的,隐式声明或者在全局环境下声明的变量是挂在全局对象上的。
ES6规定,var命令,function命令以及隐式声明的全局变量,依旧是全局对象的属性;而let命令、const命令、class命令声明的全局变量,不属于全局对象的属性。
var a = 1;
console.log(window.a) // 1let b = 1;
console.log(window.b) // undefined
函数的形参
函数的形参,隐藏着在函数一开始声明了这些形参对应的变量。
function a(x,y){}
可以看成
function a(){var x=arguments.length <= 0 || arguments[0] === undefined ? undefined : arguments[0];var y=arguments.length <= 1 || arguments[1] === undefined ? undefined : arguments[1];
}
当然在ES6下默认声明就是用的let了,所以函数a变成:
function a(){let x=arguments.length <= 0 || arguments[0] === undefined ? undefined : arguments[0];let y=arguments.length <= 1 || arguments[1] === undefined ? undefined : arguments[1];
}
所以在ES6中会有以下几个问题:
function a(x = y, y = 2) {return [x, y];
}a(); // 报错,给X赋值时y还未被let声明。 function a(x,y) {let x;//相当于重复声明,报错。
}
JavaScript中的变量声明相关推荐
- ES5和ES6中的变量声明提升
ES5和ES6中的变量声明提升 Example1: a=2; var a; console.log( a ); //结果为2 Example2: console.log( a ); //结果是unde ...
- javascript基础系列:javascript中的变量和数据类型(一)
javascript基础系列:javascript中的变量和数据类型(一) 今天开始去重新系统温习一遍js基础,并作下记录 javascript是由三部分组成: ECMASCRIPT(ES): 描述了 ...
- javascript中的变量如果没有定义就使用的话
javascript中的变量如果没有定义就使用的话 那么这个变量将成为全局变量 是不是这样的呢 转载于:https://www.cnblogs.com/virusswb/archive/2008/03 ...
- 如何在JavaScript中检查变量是否为整数?
本文翻译自:How to check if a variable is an integer in JavaScript? How do I check if a variable is an int ...
- 在javaScript中,变量名和函数名不能重名
直接上代码和截图 在javaScript中,变量的名字和函数的名字不能取一样的名字(即变量名和函数名不能重名) <script type="text/javascript"& ...
- javascript中对变量类型的判断
在JavaScript中,有5种基本数据类型和1种复杂数据类型,基本数据类型有:Undefined,Null,Boolean, Number和String:复杂数据类型是Object,Object中还 ...
- javascript中对变量类型的推断
本文正式地址:http://www.xiabingbao.com/javascript/2015/07/04/javascript-type 在JavaScript中,有5种基本数据类型和1种复杂数据 ...
- 如何理解JavaScript中给变量赋值,是引用还是复制
一.JavaScript中值的类型 JavaScript中的值分为2大类:基本类型和引用类型.每种类型下面又分为5种类型. 基本类型: 数字类型:Number:字符串类型:String:布尔类型:Bo ...
- 关于python中的变量声明问题
python中的变量不需要提前声明,但每个变量在使用前都必须要先赋值,这一步相当于创建变量.
- js变量传给java_如何把JavaScript中的变量值传给javabean?
恰好我碰到过类似的问题,引用一篇文章给你吧.希望能帮你~ JSP数据和JavaScirpt数据交互使用问题的一种解决方法 对于WEB程序来说,前端(JavaScript)和后端(JSP/Servlet ...
最新文章
- Android stadio 关联源码
- (转) SolrCloud之分布式索引及与Zookeeper的集成
- 2.1.决策树和随机森林
- ICS/SCADA 系统的对比
- 5个数中取三个数组合 不重复 php,PHP产生不重复随机数的5个方法总结
- SourceTree windows版本免注册免登陆使用方法
- jsTree使用记录
- 火遍全网,却被广东人嫌弃!昔日“百亿网红”,快被打回原形了
- Android虚拟化技术
- python 摄像头录制帧率_实践:用python实现把视频以帧数输出成连续的多图片
- python的调用函数_Python函数调用
- 牛客小白月赛31——补题记
- java 发送邮件多个人,java 发送邮件(支持多附件,抄送人等功能)
- linux 统计代码行数,shell 命令统计代码行数的简单代码
- EI、SCI和ISTP检索论文的收录号和期刊号查询方法
- 3D 打印没那么玄乎
- Linux的基本使用和程序部署
- 正片工艺、负片工艺,这两种PCB生产工艺的差异到底是什么?
- H3C-S5560交换机设置
- NOIP是什么?全国青少年信息学奥林匹克联赛各区特派员联系名单大全!