Javascript入门基础——作用域

前言

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()的用法。

相关推荐
轻口味30 分钟前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王1 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发1 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
真滴book理喻4 小时前
Vue(四)
前端·javascript·vue.js
程序员_三木5 小时前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
开心工作室_kaic6 小时前
springboot476基于vue篮球联盟管理系统(论文+源码)_kaic
前端·javascript·vue.js
川石教育6 小时前
Vue前端开发-缓存优化
前端·javascript·vue.js·缓存·前端框架·vue·数据缓存
搏博6 小时前
使用Vue创建前后端分离项目的过程(前端部分)
前端·javascript·vue.js
温轻舟7 小时前
前端开发 之 12个鼠标交互特效上【附完整源码】
开发语言·前端·javascript·css·html·交互·温轻舟
web135085886357 小时前
2024-05-18 前端模块化开发——ESModule模块化
开发语言·前端·javascript