再JavaScript中,变量是用来保存数据的一种占位符,它是松散类型的。它可以保存任意类型的数据,也可以再任意时间点去改变它所保存数据的类型。再ECMAScript中有三个关键字可以声明变量,var、let、const。var是ECMAScript6之前唯一声明变量的关键字,而let和const是ECMAScript6之后出来的两种新的声明变量的关键字
var关键字
声明一个变量,是一个关键字 var 后面再跟上一个变量名(标识符)
// 一个声明变量的关键字(如var)后面跟着一个标识符(或者称为变量名)
var a = 10
上面的例子中相当于定义了一个变量a,然后再初始化的时候给它赋值了一个Number类型的数据10,如果不给它初始化的值,那么JavaScript会给变量保存一个值undefined
因为再js中变量是松散类型的,所以再之后也可以更改变量的数据和数据类型。
// 一个声明变量的关键字(如var)后面跟着一个标识符(或者称为变量名)
var a = 10
a = 'h1'
但是这样是不推荐的,当我们再项目中定义一个变量,最好就是将这个变量就定下来之后它是使用什么数据类型,这也算是一种开发规范
var的声明作用域
var声明的变量,会成为一个函数的局部变量。再函数外部是无法访问的。访问了就会报错
function fun () {
var a = 10
}
fun()
console.log(a) // 报错
声明了一个函数,调用这个函数会创建一个变量a。但是再执行完这个函数的时候,也会销毁这个变量a。如果再函数中没有用关键字声明的变量,这个变量会变成全局的变量
function fun () {
a = 10
}
fun()
console.log(a) // 10
var声明提升
使用var声明的变量,js会将它拉到到该作用域的顶部。
console.log(a) // undefined
var a = 10
上面的也不会报错,js再解析的时候会将上面一段代码进行改造,等价于下面这个例子
var a
console.log(a) // undefined
a = 10
不管你再这个作用域的哪里声明一个var的变量,js都会将这个变量拉到该作用域的顶部,这种效应叫做变量的提升
let关键字
let的作用跟var差不多,也是声明一个变量。但是let跟var有很多不一样的地方
let的作用域
没错,let有自己独特的作用域。let声明的范围叫做块级作用域
{
let a = 10
}
console.log(a) // 报错
{
var b = 10
}
console.log(b) // 10
let只用声明再带有{}的地方,会形成一个块状的作用域。再外部就无法访问到这个变量。但是var是没有这种作用域,他只有函数作用域。而块级作用域也是函数作用域的子集,所以这个作用域也适用于let声明的变量
let不能重复声明
再一个作用域里面不可以声明两个变量名一样的let变量。如果声明了会报错,但是var则不会
let a = 10
let a = 'hq' // 报错
// 哪怕你是使用了混合声明,var加let也会报错
var a = 10
let a = 'hi' // 报错
// JavaScript引擎会根据声明变量的作用域来判断是否是重复声明,所以嵌套了作用域来重复声明就不会报错
if (true) {
let a = 10
console.log(a) // 10
}
let a = 'h1'
console.log(a) // h1
暂时性死区
使用let声明的变量,不会像var一样进行会被提升
// let声明不可以再它之前使用
console.log(a) // 报错
let a = 10
// var声明可以使用,不会报错
console.log(b) // 10
var b = 10
再JavaScript引擎解析的时候也会注意let声明的变量,但是再这之前是不允许再前面使用这个变量的,关于这种情况被称为 ”暂时性死区“,在此阶段引用任何后面才声明的变量都会抛出 ReferenceError
全局声明
let声明的变量跟var声明的变量再全局声明的情况也有所不也一样。使用var声明的变量会变成window的属性,但是let不会
let a = 10
var b = 20
console.log(window.b) // 20
console.log(window.a) // undefined
const关键字
const关键字和let关键字基本相同,但是使用它的时候必须同时初始化好要报错的数据,并且再之后不能修改const的数据
// 必须初始化要保存的数据
const a // 报错
// 初始化好了以后不能进行修改
const b = 10
b = 20 // 报错
但是有一点,如果const声明的是一个对象,那么你可以进行修改对象里面的数据。因为变量保存的是一个指针,而不是数据本身。所以只要你不将这个变量重新赋值另一个对象,就不会报错
// 这样操作不会报错
const obj = { a: 10 }
obj.a = 20 // 不会报错
console.log(obj) // { a: 20 }
// 但是这样操作就不行
const obj = { a: 10 }
obj = { a: 20 } // 报错,改变了指针的指向
声明的方式
不要使用var声明
再声明变量的方式上面,es6为我们提供了let和const可以有助于我们提供代码的质量。这两种变量声明让变量有了更明确的作用域、声明位置,以及不变的值。相比于var声明变量的一些怪异行为,let和const提高了我们代码的质量。所以再声明变量的时候不要使用var声明,多使用let和const声明
先使用cosnt 再使用let
再些代码的时候,我们应该优先考虑使用const来声明变量。只有再知道后期变量会发生改变的时候再使用let。这样可以避免因意外赋值导致的非预期行为。这样可以让开发者更有信心地推断某些变量的值永远不会变,提高我们代码的质量
数据保存的差异
我们都知道JavaScript的数据类型分为7种数据类型,其中六种原始类型 一种引用类型
原始类型(简单类型)
- String
- Number
- Boolean
- Undefined
- Null
- Symbol
引用类型(复杂类型)
- Object
而变量就是用来保存这些数据类型,便于开发者去使用。每一个变量只不过是保存一个任意数据类型的占位符
变量在保存和复制原始类型和引用类型有着区别
保存值
-
变量保存原始类型的数据,是保存这个类型的值。所以我们可以直接通过变量来操作这个值
-
变量保存引用类型的数据,是保存的这个类型的引用,不是保存这个类型的值。因为在JavaScript中Object是保存在内存里面 的,但是JavaScript是不允许开发者直接去访问这个内存位置。所以保存的是这个类型的引用
复制值
- 保存了原始类型的变量,在通过变量把一个原始值赋值到另一个变量时,原始值会被复制到新变量的位置。在内存中会多出一份数据
// str和str2是两个独立的互相不干扰
const num1 = 1
let num2 = num1
num2 += 1
console.log(num2) // 2
console.log(num1) // 1
- 保存了引用类型的变量,通过它来赋值到另一个变量,也会把这个变量的值赋值到新变量。因为引用类型的变量保存的是一个指针,所以在这个过程中实际上两个变量指向的是一个数据。内存中不会再创建出一份数据
// 因为obj1只不过是保存的一个引用(指针),所以obj2被赋值了一个指针。这个指针指向了一个对象
// 所以它们两个修改对象里面的属性,都会互相影响
const obj1 = { a: 1 }
const obj2 = obj1
console.log(obj1 === obj2) // true
obj2.a = 2
console.log(obj2) // { a: 2 }
console.log(obj1) // { a: 2 }
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!