JavaScript:变量的作用域,window对象,关键字var/let与function
为什么要将这些内容放在一起,因为他们都跟初始化有关系,我们慢慢说吧。
我们在代码中,都会声明变量、函数和对象,然后由浏览器解释器(下面简称浏览器)执行;
我们还说过,变量和对象的内存结构;
那么,是什么时候,我们声明的变量和对象,被浏览器分配内存了呢?
我们使用不同的声明方式,浏览器分配内存的顺序是一样的吗?
window对象
我们先来看一个对象window
,这个对象代表什么呢?
顾名思义,它代表一个窗口,一个浏览器窗口;
当我们用浏览器打开一个页面的时候,这个window
对象就被初始化创建了;
这个window
对象,出生就自带很多方法,包括JS内置函数和浏览器窗口函数;
所以下面的代码才能够在什么都没有的情况下,输出window
对象:
可以看到,alert()
也是window
对象的一个方法,其实console.log()
也是;
也就是说,上面的代码,其实是window.console.log()
,只是省略了window
而已;
window
对象是一个非常值得细致研究的对象,但是这里就不赘述了,我们还有很多内容要说;
总之记住一点,window
对象代表的是整个浏览器窗口,它的范围是最大的,它是最早被创建的对象;
变量的作用域
变量的作用域,其实就是指它的可见性,分为全局作用域和局部作用域:
局部作用域
先来说明一下代码块的概念;
凡是用大括号
{}
括起来的都是代码块,包括函数体、循环体,以及大括号本身等等;在代码块中声明的变量,它就只在代码块中可见,代码块外面是无法访问到的;
- 因为代码块只会在执行时用到,所以代码块中的变量的生命周期,也就是执行代码块的时候才会创建,而执行结束以后就会被垃圾回收;比如调用函数时,变量被创建,调用结束,变量就会被垃圾回收;
- 因为大括号可以嵌套,所以外层代码块的变量,内层代码块可以访问到;但是内层代码块的变量,外层代码块访问不到;
- 因为内外层代码块的可见性不一致,内层代码块可能创建和外层代码块同名的变量,此时内层代码块使用变量时,采用就近原则,也即使用离内层代码块最近的变量;
具体看下面的代码吧:
如上图所示,每个代码块中的变量a的作用域,都用框表示出来了;
值得一提的是,因为函数的特殊性,函数的局部性比其他代码块更强,这在关键字
var
那里体现的最明显。全局作用域
那么全局作用域的概念就很清晰了,不在任何
{}
代码块中的,直接在script标签中声明的变量,都具有全局作用域;那么它的生命周期,也就是打开一个浏览器窗口的时候被创建,关闭一个浏览器窗口时才会被垃圾回收;
关键字var和let
还记得我们声明变量的三种方式吗(因为const和let的行为一致,这里就不讨论const了)?
我们先讨论全局作用域的变量声明的区别:
不使用关键字
可以看到,这种声明方式,变量会成为
window
对象的属性,也就是随着window
对象一起初始化了;但是图二告诉我们,它似乎不能被访问,即此时内存并没有变量a,所以输出了
a is not defined
,这是为什么?我也不知道;所以非常不推荐这种声明方式;
使用关键字
var
可以看到,这种声明方式,变量会成为
window
对象的属性,也就是随着window
对象一起初始化,开辟了一块内存空间用来存储变量a;但是此时变量a还没有被赋值,所以输出了
undefined
,并不会报错;这也是为什么不推荐使用这种方式来声明变量,因为它的全局作用域太大,甚至在被赋值前,就可以访问而不报错;
使用关键字
let
可以看到,这种声明方式,变量不会成为
window
对象的属性;但是此时变量a,实际上已经开辟了内存区域了,但是还没有初始化,所以才会报错
Cannot access 'a' before initialization
;这是一种符号大多数编程语言的关于变量声明的处理方式,也是ES6新推出的,用来避免
var
的声明方式,也是被推荐的声明方式;
再来说一下局部作用域的一些特殊情况,主要是关键字var
:
先看下面代码的输出结果:
可以看到,哪怕是在代码块中,使用var
和无关键字的声明方式,依然还是会成为window
对象的属性,具有全局作用域;而let
声明的变量,就具有正常的局部作用域。
再看下面代码的输出结果:
可以看到,在函数体的代码块中,三种声明方式具有相同的局部作用域,函数体外部都访问不到;
这说明,var
虽然在其他代码块中不具有局部作用域,但是在函数体中却具有局部作用域,可以称之为函数作用域;
总结:
- 除函数体外,在任何地方使用
var
或者无关键字的声明方式,变量都是作为window
对象的属性,具有全局作用域; - 在函数体中,无论何种声明方式,都是局部变量,具有局部作用域;
let
以及const
的作用域表现,是最正常的,符合大多数编程语言对变量作用域的定义;- 推荐使用
let
以及const
来声明变量,酌情考虑使用var
来声明变量,最好不要使用无关键字的方式来声明变量;
关键字function
声明一个函数的时候,我们可以使用关键字function
进行声明;
我们先看下面代码的输出结果:
按照代码从上至下的顺序执行,我们可以看到,尽管函数aaa
的声明代码,是在打印和调用aaa
的代码之后,依然打印和调用成功了;
说明,当浏览器执行代码的时候,函数声明是先执行的,并且它成为了window
对象的一个方法;
注意:
- 只有使用
function
关键字才会这样,使用函数表达式和箭头函数去声明函数的时候,因为有个赋值给变量的操作,所以它是一个执行语句,浏览器会按照顺序去执行; - 只有直接在script标签中声明才会这样,在其他任何代码块即在
{}
中进行声明,因为代码块也是执行语句,浏览器会按照顺序去执行;
JavaScript:变量的作用域,window对象,关键字var/let与function的更多相关文章
- javascript变量的作用域
javascript变量的作用域 基本类型和引用类型 基本类型值指的是简单的数据段,而引用类型值指的是那个可能由多个值组成的对象 讲一个值赋值给变量时,javascript解析器首先要确定是基本类型 ...
- javascript 函数初探 (三)--- javascript 变量的作用域
javascript 变量的作用域: 这是一个至关重要的问题.特别是当我们从别的语言转向javascript时,必须要明白一点,即在javascript中,变量的定义并不是以代码块作为作用域的,而是以 ...
- let,const 声明的变量不会绑定给window对象 而var会
先来看一道题 let id = 2; let json = { id: 1, show:function(){ setTimeout(function(){ console.log(this.id); ...
- 深入理解 JavaScript 变量的作用域和作用域链
一个变量的作用域(scope)是程序源代码中定义这个变量的区域.简单的说,作用域就是变量与函数的可访问范围.全局变量拥有全局作用域,在JavaScript代码中的任何地方都有定义.局部变量是在函数体内 ...
- JavaScript变量的作用域和函数的作用域的区别
变量作用域和函数作用域都涉及到变量值的变化,本文旨在让大家明白他们之间的区别 变量的作用域: 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接 ...
- javascript变量、作用域和内存问题......
1基本类型是指那些保存在栈内存的简单数据段,引用类型是指那些保存在堆内存中的对象,变量中保存的实际上只是一个指针. 2javascript中5种基本数据类型Undefined,Null,Boolean ...
- JavaScript 变量、作用域及内存详解
基本类型值有:undefined,NUll,Boolean,Number和String,这些类型分别在内存中占有固定的大小空间,他们的值保存在栈空间,我们通过按值来访问的. (1)值类型:数值.布尔值 ...
- 深入浅出 JavaScript 变量、作用域和内存 v 0.5
本文主要从原理入手分享变量和作用域的相关知识,最后结合本文所分享知识,再次深入了解下闭包的运行原理. 主要参考<JS高级程序设计> <JS权威指南> <高性能 JS> ...
- 【javascript 变量和作用域】
今天学习了javascript 的变量和作用域的基本知识,对于以前在开发中遇到的一些不懂的小问题也有了系统的认识,收获还是比较多的. [基本类型和引用类型] ECMAScript 变量可能包含两种不同 ...
- [从jQuery看JavaScript]-变量与作用域链
jQuery片段: var // Will speed up references to window, and allows munging its name. window = this, // ...
随机推荐
- C#-7 结构和枚举
一 什么是结构 结构是程序员定义的数据类型,有数据成员和函数成员,和类非常类似. 类是引用类型,而结构是值类型: 结构和类一样可以实现接口: 结构是隐式密封的,不能被派生: 结构类型的变量不能为nul ...
- docket打包镜像内部报错
临时记录,后面再完善 对于前端docker一般不太熟悉,当我们想要打包镜像的时候会去找教程,我按着教程去打包一个使用KOA框架搭建的node服务. 这是一个 koa + ts + pm2的项目 结果出 ...
- MatrixOne从入门到实战04——MatrixOne的连接和建表
MatrixOne从入门到实战--MatrixOne的连接和建表 前景回顾 前几篇文章,为大家介绍了MatrixOne这个产品,以及编译.部署MatrixOne的服务. 直通车: MatrixOne从 ...
- ASP.NET Core :缓存系列(四):内存缓存 MemoryCache
System.Runtime.Caching/MemoryCache ICacheEntry 接口中的属性:具体设置过期时间 可以参考:微软文档ICacheEntry 接口 缓存基本使用 (一) 绝对 ...
- IDEA 调试起来太费劲?你需要了解这几招!
各位好啊,我是会编程的蜗牛,我们在使用IDEA开发java项目时,经常需要用到IDEA的调试功能,不过平时我们用的调试方法可能过于简单了,其实IDEA还给我们提供了非常强大的调试功能,下面让我来看一看 ...
- SSM(Spring,SpringMVC,Mybatis)框架整合项目
快速上手SSM(Spring,SpringMVC,Mybatis)框架整合项目 环境要求: IDEA MySQL 8.0.25 Tomcat 9 Maven 3.6 数据库环境: 创建一个存放书籍数据 ...
- 开源动态可监控线程池DynamicTp介绍
前言 使用线程池 ThreadPoolExecutor 过程中你是否有以下痛点呢? 代码中创建了一个 ThreadPoolExecutor,但是不知道那几个核心参数设置多少比较合适 凭经验设置参数值, ...
- Java I/O(1):模型与流
在1990年以前,有一帮工程师们认为未来(1990年以后)会有很多小型设备需要得到电脑操控(不得不说,想法非常超前),鉴于当时市面上并没有任何一款编程语言能够跨平台,而且能够在诸如烤面包机这种小型设备 ...
- (二)Three光线检测-实现摄像机向鼠标点击位置滑动动画
(二)Three.js光线检测 摘要:使用three.js中的光线检测 Raycaster() ,实现一下效果: 通过点击处的坐标,修改摄像机位置,实现摄像机由远及近的过渡动态效果(由远景到近景) 1 ...
- Ruoyi表单构建
Ruoyi表单构建通过拖动组件就能自动生成前端代码,很方便,所以本文简单通过上层函数源码来梳理一下大致流程,如有需要再自行仔细一行行分析底层代码. 组件拖动 实现组件拖动功能主要依赖第三方库:VueD ...