变量
var
变量声明
变量用于存储数据值,JavaScript
可以使用 var
关键词来声明变量
声明之后,变量是没有值的(技术上,它的值是 undefined
),我们可以在声明变量的同时进行赋值:var person = 'Bill Gates';
(变量的声明一般都是直接包含声明和赋值)
可以在一条语句声明多个变量:声明也可以横跨多行,每行以逗号结尾:
var person = 'Bill Gates', carName = 'porsche';
重复声明的变量会继承之前的值,除非重新声明时又赋了新的值
变量声明的变量名,js
会自动的通过内存地址将存储的内容进行拿取
在js
中,变量的声明是弱类型的,不需要指定变量是什么类型的,变量的类型是根据其值来发生改变的
变量提升
在代码执行之前,解析器会将全部代码先分析一遍,在执行的过程中,就会将变量声明进行提升
var web = 'baidu.com'
console.log(web)
var class = 1
上述代码会因为
class
是特殊字符不能作为变量命名,导致控制台报错,同时控制台不会执行前面的打印操作,是因为变量声明会被提升到前面,前面的内容报错了,后续的打印操作也就不会执行
变量声明是可以被提升的,但是变量赋值是不能被提升的
console.log(web)
var web = 'baidu.com'
// 结果打印的是undefined
上述的代码可以正常在控制台中进行打印,因为变量声明会被提升到前面,但是打印的结果是undefined,是因为变量赋值操作是不能被提升的
console.log(web)
var web
web = 'baidu.com'
// 结果打印的是undefined
如果某一行没有执行,但是这一行有变量声明,在解析时还是会将其变量声明进行提升
if(false){
var web = 'baidu.com';
}
console.log(web)
// 结果打印的是undefined
let
和const
变量声明
let
声明的变量只在let
命令所在的代码块内有效;const
声明一个只读的常量,一旦声明,常量的值在同一个作用域中就不能改变,如:jsconst web = 'baidu.com'; web = '百度'; // 结果报错
在不同的作用域
const
定义的变量值是可以重新声明赋值改变的:jsconst web = "baidu.com"; function show() { const web = "百度"; }
结果不报错,严格意义上两个
web
都不是同一个变量了,因为在不同的作用域中
var
变量声明是可以进行变量提升的,变量提升带来的不全是好处,如:某一行没有执行,但是这一行有变量声明,为了解决这个情况,就有了let
变量声明,let
变量声明没有变量提升,必须先声明再使用,否则会报错
let web = 'baidu.com';
console.log(web)
TDC
暂时性死区
TDC
暂时性死区也叫临时性死区(Temporal Dead Zone
)
let
和const
声明的变量不会进行变量的提升,如果在声明前使用就会报错,因为这个变量此时还存在与暂时性死区里面
let web = 'baidu.com';
function func(){
console.log(web);
let web = '123.com';
}
func();
// 结果报错
如果在一个局部的区域中使用了外部声明的变量,在块区域中也有声明语句,声明语句必须放到使用之前
function run(a = 3, b = a){}
run(); // 不报错
function run(a = b, b = 3){}
run(); // 报错
var
,let
和const
的共同点
局部空间是可以访问到外部的公共空间的,局部中可以调用(访问到)外部全局声明的变量
jslet/var/const web = 'baidu.com'; function show() { consloe.log(web) } show() // baidu.com
如果内部有该变量的重新声明,那么内部的调用内部声明的变量,外部调用外部声明的变量;如果内部不是声明,而是重新给变量赋值,那么改变的是这个全局变量(总而言之,在函数体内部声明变量后,这个函数体就是这个变量的私有领地,新开辟空间来存储数据,如果不声明,调用变量时,就会去上一级空间去进行查找)
变量的全局污染
在js
中变量的命名如果前面没有加变量的声明符是不会报错的:web = 'baidu.com'
(尽量避免这种写法,这种写法会导致变量的全局污染)
当我们从外界调用这个变量时,如果这个变量使用上述不规则的写法:
// one.js
function show() {
web = 'baidu.com'; // web变量污染到了全局
}
<!--two.html-->
<script src="one.js"></script>
<script>
web = '百度';
show(); // 变量污染到了全局
console.log(web); // 结果显示为baidu.com
</script>
为了变量不污染全局,一定要对变量进行声明,声明了变量之后,该变量只在其局部可以调用,不会污染全局
块作用域
JavaScript
中的作用域:
全局作用域:在全局(函数之外)声明的变量有全局作用域,该变量可以在
JavaScript
程序中的任何位置访问函数作用域:在局部(函数内)声明的变量有局部作用域,该变量只能在它们被声明的函数内访问
块作用域:在块
{}
内声明的变量无法从块外进行访问,块作用域可以理解为{}
中的内容作用域
let
和const
关键词在 JavaScript
中提供了块作用域(Block Scope
)变量(和常量);var
是没有块作用域的
{
var x = 10;
}
// 此处可以使用 x
{
let x = 10;
}
// 此处不可以使用 x
因为
let
变量声明是有块作用域的,不会对全局造成影响,后续都推荐使用let
代替var
进行变量声明
在块作用域内使用 const
声明与 let
声明变量类似,const
不能更改常量原始值,但我们可以更改或添加常量对象的属性,但是无法重新为常量对象赋值
const PI = 3.141592653589793;
PI = PI + 10; // 会出错
// 创建 const 对象:
const car = { type:'porsche', model:'911', color:'Black' };
// 可以更改属性:
car.color = 'White';
// 可以添加属性:
car.owner = 'Bill';
// 不能重新赋值,报错
car = { type:'Volvo', model:'XC60', color:'White' };
通过const
创建的常数数组是可以更改其数组的元素的,同理也无法重新为常量数组进行赋值:
// 创建常量数组:
const cars = ['Audi', 'BMW', 'porsche'];
// 可以更改元素:
cars[0] = 'Honda';
在同一作用域或块中,不允许将已有的
var
或let
变量重新声明或重新赋值给const
在同一作用域或块中,为已有的
const
变量重新声明或赋值是不允许的在另外的作用域或块中重新声明
const
是允许的
循环作用域
在循环中使用的变量使用 var
,会重新声明了循环之外的变量:
var i = 7;
for (var i = 0; i < 10; i++) {
// 一些语句
}
// 此处i为 10
在循环中使用的变量使用let
,不会重新声明循环外的变量:
let i = 7;
for (let i = 0; i < 10; i++) {
// 一些语句
}
// 此处i为 7
window
全局对象
用var
声明变量时,就会将该对象保存到window
全局对象当中,我们可以通过window.变量
,读取到这个变量
var web = 'baidu.com';
console.log(window.web)
// 结果打印 baidu.com
window
窗口对象有其特有的内置对象,如screenLeft
,表示距离屏幕左侧的像素距离,如果按照上述进行声明变量,可能会导致其特有的内置对象失效,这是var
声明变量可能会出现的问题,因为通过var
声明变量,会被放到全局中,作为一个window
的一个属性
但是通过let
这样声明对象,是不会出现这样的问题,通过window
窗口调用,返回的是undefined
在 HTML
中,全局作用域是window
对象,通过 var
关键词定义的全局变量属于 window
对象,通过 let
关键词定义的全局变量不属于 window
对象
var carName = 'porsche';
// 此处的代码可使用 window.carName
let carName = 'porsche';
// 此处的代码不可使用 window.carName
如果把值赋给尚未声明的变量,该变量将被自动作为 window
的一个属性:
var var1 = 1; // 不可配置全局属性
var2 = 2; // 没有使用 var 声明,可配置全局属性
console.log(this.var1); // 1
console.log(window.var1); // 1
console.log(window.var2); // 2
delete var1; // false 无法删除
console.log(var1); // 1
delete var2;
console.log(delete var2); // true
console.log(var2); // 已经删除 报错变量未定义
变量的重复声明
在程序中的任何位置都允许重新声明 JavaScript
var
变量,系统是不会进行报错的,其变量值是最后一次声明的值,之前声明的值会被覆盖掉
但是通过let
和const
在同一个作用域中声明变量,如果重复声明,系统会给出报错提示:Identifier 'web' has already been declared
在相同的作用域/块中,通过
let
重新声明一个var
变量是不允许的在相同的作用域/块中,通过
let
重新声明一个let
变量是不允许的在相同的作用域/块中,通过
var
重新声明一个let
变量是不允许的在不同的作用域/块中,通过
let
重新声明变量是允许的
变量冻结
我们知道通过const
声明常量,其值是不能改变的,但是我们可以改变其属性的值,如果我们想要其属性的值都不能改变,我们就要通过变量冻结的方法来锁定变量,使其在后续过程中都不能发生改变
const HOST = {
url: 'baidu.com',
port: 8080
};
// HOST.url的值目前是可以进行改变的
Object.freeze(HOST) // 变量冻结,之后HOST的所有属性值都不可发生改变
传值和传址
对于基本量,如数值,字符串,进行传值,系统会新开辟一块空间
let a = 1;
let b = a;
之后b发生变化,a不受到影响
对于比较大的空间,如对象,进行传址,会共用地址,不会开辟一块新空间
let a = { web: ’baidu.com‘ };
let b = a; // 共用一个内存地址,当b的值发生改变时,会使a的值也发生改变
b.web = '123.com';
console.log(a, b) // { web: '123.com' }, { web: '123.com' }
null
和undefined
null
表示有值undefined
表示没有值
当一个变量只是声明没有赋值时,返回的是undefined
对于变量,在不进行赋值时:
如果想要该变量保持引用的类型,可以在初始的时候定义成
null
,如:let config = null
,也可以用另外一种写方法:let config = {}
如果想要该变量保持基本的类型,可以在初始的时候定义成
undefined
,如:let config = undefined
,也可以用另外一种写方法:let config = ''
对于一个函数,如果函数没有返回值,就会返回undefined