让天下没有难学的js之JavaScript中变量的那些事

本篇文章面向群体:入门级
难度等级:★☆☆☆☆
内容较多,建议点赞收藏后阅读

什么是变量

变量做为js中最多见也是咱们最先接触的js知识点,相信你们都不陌生,变量几乎存在于全部的编程语言中,百度百科中对于变量的解释为 变数或变量,是指没有固定的值,能够改变的数。变量以非数字的符号来表达,通常用拉丁字母。 而JavaScript中的变量是松散类型(弱类型)的,所谓松散类型就是能够用来保存任何类型的数据,在声明变量时无需指定变量的类型。因此,当咱们声明一个变量以后,能够存储任意类型的数据。javascript

怎么去声明一个变量

变量名

在js中声明一个变量一般经过关键字加一个变量名的形式来声明一个变量,那对于变量名在js中是如何要求的呢?html

  • 变量名必须以字母、下划线(_)或者美圆符($)开头,后面能够跟字母、下划线、美圆符或者数字
  • 变量名的长度不能超过255个字符
  • 变量名必须区分大小写
  • 变量名中间不可有空格换行符及其余标点符号
  • 不能使用脚本语言保留的关键字做为变量名,如true、false、function等(具体关键字列表可参考菜鸟教程JavaScript 保留关键字

除了这些js明文规定的变量命名规则以外,为了代码可读性更高,咱们一般也对变量命名有行业通用的命名规范。java

  • 尽可能采用符合当前语义的单词进行命名,如agetime,避免使用无心义的字符组合,如aaabbb
  • 因为部分框架可能使用$做为关键字,因此咱们也应尽可能避免使用$做为变量名
  • 若是命名单词超过两个单词,尽可能采用驼峰法命名,如userAgemyFirstName
  • 尽可能避免使用中文做为变量名,尽管那样不会报错

声明变量

上面说了,js声明变量的方法为关键字加一个变量名,说完了变量名,咱们就来讲一下声明变量的关键字,js中声明变量的关键字有如下三种es6

var

var关键字是咱们学习js最早接触也是早期声明变量最为经常使用的关键字,使用方法直接在var关键字后面直接跟变量名便可,如编程

var message = 'hello world'
console.log(message) // hello world

var 关键字特色框架

  • 可重复声明,但并无什么卵用
  • 声明后的变量可修改
var message = 'hello'
message = 'world'
console.log(message) // world
  • 有初始值,每个用var声明的变量初始值均为undefined
var message
console.log(message) // undefined
  • 可同时声明多个变量
var message, test, handleName
console.log(message) // undefined
console.log(test) // undefined
console.log(handleName) // undefined
  • var 关键字能够省略
message = 'hello'
console.log(message) // hello

// js 中若是省略var关键字,则会自动建立全局变量
function foo() {
    message = 'hello'
    console.log(message) // hello
}
foo()
console.log(message) // hello

// 若是使用,则会建立当前做用域的变量
function foo() {
    var message = 'hello'
    console.log(message) // hello
}
foo()
console.log(message) // message is not defined

<span style="color:red">*</span> 注意,在严格模式下不可省略关键字,不然会报错编程语言

let

let 关键字是ES2015(ES6) 新增长的重要的 JavaScript 关键字,用法和 var 同样函数

let message = 'hello world'
console.log(message) // hello world

let 关键字与var不一样的地方学习

  • 不可重复声明,已经声明过的变量再次声明会报错(在同一做用域内)
var message
let message // Identifier 'message' has already been declared

let test = 'test'
let test = 'hello' // Identifier 'test' has already been declared
  • let 所声明的变量,只在 let 命令所在的代码块内有效
{
  let a = 10;
  var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

利用 let 的这一特性能够解决很经典的一个问题spa

for (var index = 0; index < 6; index++) {
  setTimeout(function() {
    console.log(index)
  }, 100)
}

这段代码的结果输出的是6个6,这是由于这里的index是用 var 定义的,每一轮循环所用的index都是全局变量,因此等到100毫秒后执行的时候,index已经循环完变成了6,那么利用 let 仅在当前代码块有效的这个特性,就能够很好的解决这个问题

for (let index = 0; index < 6; index++) {
  setTimeout(function() {
    console.log(index)
  }, 100)
}
// 0 1 2 3 4 5

由于 let 仅在当前代码块有效,因此这里每一轮循环都至关于定义了一个新的index,因此最后输出的时循环时候的值。你可能会问,若是每一轮循环的变量i都是从新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是由于 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

const

const 关键字是ES2015(ES6) 新增长的重要的 JavaScript 关键字,用法和 var 同样,只不过 const 生成的是一个或多个常量,在有些时候,咱们定义的值不但愿被覆盖或者修改,咱们就能够用 const

const message = 'hello world'
console.log(message) // hello world

const 关键字 和 var 关键字不一样的地方

  • 不可重复声明
  • 声明时必须初始化,不然会报错
const a // Missing initializer in const declaration
const b = 'test' // 正确
  • 声明的常量不可进行赋值修改
const a = 'hello'
a = 'world' // Uncaught TypeError: Assignment to constant variable.
其实const声明的常量并不是严格意义上的常量,由于当咱们用const定义一个常量的值为引用类型(下面会讲基本类型和引用类型)时候,虽然咱们不能进行从新赋值,但咱们能够修改引用类型的值。
const a = {
    name: '小明'
}
a.name = '小豪'
console.log(a.name) // 小豪

变量的值:基本类型与引用类型

咱们知道,js中的值能够保存全部数据类型,那么js中的数据类型又都有什么呢?
JavaScript中的数据类型有六种,其中有五种简单数据类型(也叫基本数据类型),还有一种复杂的数据类型——对象(Object),因为本文主要讲的是变量相关知识,因此对数据类型不深刻讲解,知识大概说一下。

基本类型

五种基本的数据类型:Undefined、Null、Boolean、Number和String。这5种基本数据类型是按值访问的,由于能够操做保存在变量中的实际的值。咱们就直接按正常思路来就好了。

var a = '小明'
var b = a
a = '小豪'
console.log(b) // '小明'

引用类型

因为对象的知识相对较多,后续会有专门的文章进行介绍总结。

若是有点基础同窗都知道,原始类型存储的是值,对象类型存储的是地址(指针),
那么当咱们定义一个变量的值为对象的时候,因为存储的实际是这个对象在内存中的地址,至关于咱们在这里只是引用了这个对象,因此在对一些变量进行复制赋值和修改时候就会出现一些意想不到的事情,好比下面的代码

var a = {
  name: '小明'
}
var b = a
b.name = '小豪'
console.log(a.name) // 小豪

在上面的例子中,咱们把a赋值给b,实际上只是把a所引用的对象地址赋值给了b,这时候a和b其实指向的是一个对象,因此当咱们修改其中任何一个的时候,都是在对同一对象进行修改

这样很好的解释了咱们上面所说的const定义的常量可修改的问题,当咱们用const定义的常量为对象时,其实咱们在这个常量里保存的只是一个对象的地址,不管咱们怎么修改这个对象,const定义的常量里保存的地址是没有变化的,因此上面例子中对const定义的对象进行修改其实并无违背const定义的变量不可修改的原则,只有咱们给这个常量从新赋值一个新对象(也就是新地址)的时候,才会触发const定义的常量不可修改的规则。

变量做用域

做用域,咱们这里为了理解,能够简单的理解为做用域就是变量能够生效及访问的地方。JavaScript中分为全局做用域和局部做用域,全局做用域里的变量在全部的地方均可以访问,局部做用域只能在当前做用域被访问。

在一些相似于c语言的编程语言中,每一对花括号包裹的区域都有本身的做用域,咱们称之为块状做用域,而在JavaScript中没有块级做用域(es6以前),取而代之的是函数做用域,因此咱们一般所说的局部做用域也就是函数做用域。

var a = "hello" // 全局做用域
function foo() {
    // 在此做用域能够访问到a
    console.log(a) // 'hello'
    var b = 'world'
}
foo()
console.log(a) // 'hello'
// 因为变量b定义在函数foo内,因此在函数foo的做用域外访问不到
console.log(b) // b is not defined

在js中能够存在函数嵌套函数的状况,因此咱们很是容易见到函数做用域嵌套的状况,这时候就会造成一条做用域链,在js中,当你使用一个变量时,JavaScript引擎会首先在当前做用域内寻找,若是找不到,就会到上一层做用域寻找,若是一直找到顶层做用域(也就是全局做用域)还找不到时,就会报错。

ES2015(ES6) 新增长了 let 关键字,从而可让咱们在块级做用域(大括号)中声明变量。

变量提高

在JavaScript 中,函数及变量的声明都将被提高到当前做用域的最顶部。

//var a   <------------------
console.log(a) // undefined  ↑
var a   //  ---------------->

在上面的例子中,咱们虽然声明语句在打印语句的后面,可是咱们打印a却并无报错,就是由于这里的变量声明被提到了当前做用域的最上面,咱们称之为变量提高。

在JavaScript中 var a = 'test' 实际上是分为两步进行的,分别是变量声明 var a 和 变量赋值 a = 'test', 变量声明会被提早,可是变量赋值不会被提早,咱们来看下面的例子

console.log(a) // undefined
var a = 'test'

// 上述代码的执行步骤能够用下面的代码理解

var a
console.log(a)
a = 'test'

结合上面的函数做用域,咱们来看一下下面的例子

var a = 'test'
function foo() {
  console.log(a)
  var a = 'hello'
}
foo()

你们猜一下打印的结果是什么,没错,就是 undefined ,咱们这里定义了全局变量a,又定义了函数局部变量a,因此咱们在执行函数 foo() 时,实际上是找的函数 foo() 里的局部变量a,局部变量a经过变量提高到了函数 foo() 的顶部,可是变量赋值却没有提高,因此最后打印结果为 undefined,上面的代码能够理解为下面这样

var a = 'test'
function foo() {
  var a
  console.log(a)
  a = 'hello'
}
foo()

须要注意的是 letconst 不存在变量提高,在你定义他们以前使用会报错。比较有意思的是,letconst的报错还不同

console.log(test) // Cannot access 'test' before initialization
const test = 'hello'

console.log(message) // message is not defined
let message = 'hello'

// 若是咱们在局部做用域里写,报错就同样了
function foo() {
  console.log(message) // Cannot access 'message' before initialization
  let message = 'world'
}
foo()
做者确实基础较差,写文章更多的目的是为了提升本身的能力,可是总结写下来不免有啰嗦和失误的地方,若是能够帮到别人固然十分开心,若是你们发现什么问题也欢迎随时提出,我也会持续的学习,不断的对文章新型修改,但愿你们一块儿进步,加油
相关文章
相关标签/搜索