前言
Javascript属于是一种弱类型动态语言且在执行代码前是需要先编译的,且变量的查找会先从内到外的作用域中查找,不能从外到内查找。
什么叫弱类型动态语言呢?
当强类型动态语言声明一个变量时 var a:number=1 ,需要加上类型名(number),此时当你重新定义a='hello'时,此行代码无法运行,'hello'是字符串类型,而你定义的确实number类型,而弱类型动态语言声明一个变量时只需 var a=1,不需要加类型,并且当你修改a值时(a='hello'),可以成功修改的。
js
var a =1
a='hello'
console.log(a);
# 在Javascript中什么是作用域?又包括哪几类? 作用域(Scope)是编程中用于确定在代码中访问变量的可见性和可访问性的概念。作用域规定了程序中变量的可见范围,以及在特定位置可以访问哪些变量。
作用域
一、全局作用域
在 JavaScript 中,位于函数之外的变量被称为全局变量,它们拥有全局作用域。这意味着全局变量可以在代码的任何地方被访问,包括函数内部和外部。
js
var a = 1;//全局变量
var b = 2;//全局变量
function foo() {
console.log(a, b);
}
foo();
二、局部作用域
局部作用域是指在函数内部声明的变量,它们只能在函数内部访问,称为局部变量。
jsvar
function foo() {
var a = 2;//局部变量
console.log(a);
}
foo();
三、块级作用域
块级变量声明周期 : 从大括号开始 -> 到大括号结束。
jsif(true){
var a = 1;//全局变量
let b = 2;//块级变量(块级作用域 :只在大括号内部起作用)
console.log(a,b);//1,2
};
console.log(a);//1
// console.log(b);// b is not defined
到这儿,各位小伙伴可能就不能理解了,为什么a和b都是在if语句中定义,但a是全局变量而b却是块级变量呢,这就引出了我们今天的另外一个知识点:var有声明提升的作用,将a=1提升到作用域的顶端,成为全局变量,而函数的声明则会整体提升,但let却没有声明提升这个功能,这在后续的讲解中将为大家介绍到let、const与var声明的区别!
什么是声明提升呢?
例如下面这段代码,当我们用正常思维逻辑来解释时,这段代码是不能让人理解的,正是声明提升以及执行前先编译这两个特点的存在,使得这段代码是可以运行的,但是得出来的结果是undefined,这并不意味着是错误,而是因为在执行console.log语句前,a并没有赋到值。
js
console.log(a);
var a=1;
上面那段代码因为声明提升的原因,等同于下面这段代码,将a的声明提升到了最顶端,但是对于a的赋值却不能提升,这也是最终结果出现undefined的原因。
js
var a
console.log(a);
a =1
let及const与var声明的区别
(一)let及const不能声明提升
还是拿上一段var定义的代码来说,将var替换成let以及const,分别调试看结果。
js
console.log(a);
let a =1
js
console.log(a);
const a =1
从上面的两个调试结果我们可以看到,显示的是"cannot access 'a' before initialization",这是报错的意思,而var定义时却是说"undefined",说明let及const与var不同,var可以声明提升,而let及const不能声明提升。
(二)let及const的特点
let除了不能声明提升外,还不能同时定义两个相同的量,系统会出现报错,但用let声明一个变量,其可以修改值,下列代码中,将a的值修改为了hello。
js
let a=1
a='hello'
console.log(a);
const同样不能声明提升且不能同时定义两个相同的量,但是const也不可以修改变量值,下列代码在运行中会出现报错。
js
const a=1
a='hello'
console.log(a);
欺骗词法作用域
(一)eval()将原本不属于这行的代码放置这行
观察下列代码:
js
var b = 2; // 被覆盖
function foo(str, a) {
eval(str); // 欺骗
console.log(a, b);//输出: 1, 3
}
foo("var b = 3;", 1);
为什么得出来的(a,b)会是1,3呢?这正时因为eval()函数的作用,foo()中,str对应"var b = 3",而a对应"1",但由于eval(str)产生了欺骗,将第三行的代码替换成了"var b = 3"使得b=2的值被b=3覆盖,所以当console.log输出时,会是1,3。
(二)with()当修改对象中不存在的属性时,该属性会泄露到全局成为全局变量
观察下列代码:
js
function foo(obj){
with(obj){
a=2
}
}
var o1={
a:3
}
foo(o1)
console.log(o1);
从上面运行结果可以看出来,将o1()中a=3的值带入foo()函数中时,with修改了a的值,变成了2,这是修改o1()中有的变量。如果修改函数中没有的变量呢,输出结果会怎么样呢?看如下代码:
js
function foo(obj){
with(obj){
a=2
}
}
var o1={
a:3
}
var o2={
b:4
}
foo(o2)
console.log(a);
可以看出来,with修改foo(o2)中的a,但o2()函数中只有b=4,并没有a,所以此时修改的值a=2就会变为全局变量,当最后console.log(a)时,输出的结果就是全局变量a=2,这正是with()的用法。