声明变量var与let.const(常量)详解,堆栈详解
发布日期:2021-06-29 02:56:28 浏览次数:4 分类:技术文章

本文共 3815 字,大约阅读时间需要 12 分钟。

这里写目录标题

1.ES6简介

ECMA是一个标准 JavaScript是ECMAScript的实现。

ES6是ECMAScript的一个版本,是2015年发布的,ES2015.

let关键字

ES6新增的关键字,用来声明变量。用法类似于var,但是所声明的变量,只在let所在的代码块有效。

var a = [];    for (var i = 0; i < 10; i++) {
a[i] = function(){
console.log(i); }}a[6](); //10

var定义的变量遇到for循环的大括号是不会形成作用域的。所以在上面代码调用时,调用的是一个全局的变量。

var a = [];    for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i); }, /* a[i] = function () { console.log(i); }等于这个函数运行了6次*/ } a[6](); //6

以上代码中,i是使用let声明的,当前的i只在本轮的循环中有效。每一个循环中的i其实都是一个新的变量。所以输出的是6.(原理 let i = 0 与 a[i] 不是同一个i)

例子演示

var

for (var i = 0; i < 3; i++) {
var i = "abc"; console.log(i);//输出一次abc(原理因为输出了一次就弹出到控制台,所以循环停止) }

let

for (let i = 0; i < 3; i++) {
let i = "abc"; console.log(i);//输出3次abc }

结果:输出3次abc

原因:在代码块中的变量i与for循环中的变量i不在用一个作用域。

1.1 不存在变量提升

var 存在变量提升。即变量在声明之前使用时,值为undefined。js会将声明语句放在所有js代码之前执行。

console.log(a);var a = 10;//相等于var a;console.log(a);a = 10;

我们看下let

console.log(a);let a = 10;

结果:提示错误Cannot access 'a' before initialization(在初始化之前无法访问a)

.2 暂时性死区

var tmp = 123;    if (true) {
tmp = "abc"; let tmp; console.log(tmp); }

结果:提示错误Cannot access 'a' before initialization(在初始化之前无法访问)

使用变量时,会先寻找同一作用域下的变量。以上代码中,tmp=abc会优先寻找到下面的let tmplet tmp不存在变量提升,所以提示错误。

总结:在代码块中,使用let命令声明变量之前,该变量都是不可用的状态,在语法上,称为“暂时性死区”

.3 不允许重复声明

let a = "yasuo";let a = "jianhao"  console.log(a);/Identifier 'a' has already been declared(标识符'a'已经声明)
function show(a){
let a = 10;}show(100);过程:调用函数时将100给了a,结果发现函数里面已经定义了a函数的形参`a`与函数内部的`a`作用域相等,所以会报错。

可以这样演示

函数的形参a与函数内部的a作用域不是同一个作用域,所以不会报错。

块级作用域

.1 为什么需要块级作用域

ES5 只有全局作用域和局部作用域(函数作用域),没有块级作用域。

缺点1:内部变量可能会覆盖外层的变量

var date = new Date();function f(){
console.log(date); if(false){
var date = "今天是个好日子" }}f();//undefined

上面案例中,if代码块外部原意为使用外层的date,内部使用内部的date。但是函数执行后,结果却为undefined,原因是存在变量的提升。导致内部的date覆盖了外部的date变量

缺点2:for循环中的计数变量泄露为全局变量。

以上案例中,for·循环中的变量i只是用来作为计数使用,但是for循环执行完成后,它没有消失,而是作为全局变量仍然存在。以后可能不会再使用,造成资源的浪费。

缺点2:for循环中的计数变量泄露为全局变量。

.2 ES6块级作用域

块级作用域下的变量不会对外层的变量造成影响,同时支持多层嵌套。

if(true)let  a = "亚索";console.log(a);//报错ES6的块级作用域必须有大括号,所以使用if判断时,不可以省略大括号

练习:点击其中的任意li弹出其li的下标

    
  • 诺手
  • 狼人
  • 亚索
  • 卡莎
  • 猫咪

const声明

1.基本用法

const也是用来声明变量的,不过它声明的是一个只读的常量。一旦声明,值不可修改。

const PI = 3.1415926;// alert(PI);PI = 3.14;当改变一个常量时就会报错//Assignment to constant variable 为一个常量赋值了alert(PI)

1.2 必须初始化

const PI;//声明一个常量时就要赋值PI = 3.1415926;alert(PI);/报错 Missing initializer in const declaration  const声明中缺少初始化式

因为const声明的变量的值不可修改,所以,const一旦声明变量,则必须初始化。

1.3 一般变量名大写

const PI = 3.1415926;

这是一个规范。我们遵循,方便分辨,不是必须这样做

1.4 也有块级作用域

const与``let`相同,只会在声明的所在代码块作用域内生效。

{
const PI = 3.1415926;}alert(PI);/报错 PI未定义

1.5 不存在变量提升

alert(PI);const PI = 3.1415926;/报错   在初始化之前无法访问'PI'

1.6 不可重复声明

var PI = "3.14"; const PI = 3.1415926;

var 声明 重复时不会报错,但会覆盖上一个声明变量

1.7 对于数组和对象中的元素进行修改,不算对常量的改变

const变量保存的变量指向的值的内存地址。对于简单的数据(数值,字符串,布尔值)值保存在变量指向的内存地址。

对于复合数据类型,变量指向的内存地址,只是该对象的地址,其中的内容发生变化不会使该对象的内存地址发生变化。

堆栈知识

小知识:对象,数组,函数,数据存放在堆里面,这三个是引用值

引用值是在栈里面放堆的地址
例子:
基础类型
number(数值)
string(字符串)
boolean(布尔值)
null(空)
undefined(未定义)

引用类型

数组 array
函数function
对象Object

一、数据类型

为了更好的来阐述栈和堆,我们先来了解一下数据类型

在js中数据类型主要分为以下两大类:

基本类型:String,Number,Boolean,Null,Undefined,这5种基本数据类型它们是直接按值存放的,所以可以直接访问。引用类型:Function,Array,Object,当我们需要访问这三种引用类型的值时,首先得从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。

二、什么是栈,什么是堆

栈(stack):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;堆(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。

三、二者区别

1、缓存方式区别

1.栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放;
2.堆是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。

2、堆栈数据结构区别

堆(数据结构):堆可以被看成是一棵树,如:堆排序;栈(数据结构):一种先进后出的数据结构。

在这里插入图片描述

 

在这里插入图片描述

下面这个例子可能会认为是100,其实不是的 在这里插入图片描述引用类型中,两个变量共用一个地址的时候,两个变量都能够操作堆里面的值,看下面例子

在这里插入图片描述

转载地址:https://blog.csdn.net/z18237613052/article/details/114029023 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:ES6中变量的解构赋值,数组解构/对象解构/字符串解构/函数解构
下一篇:jQuery及下载安装使用, jquery选择器,DOM节点操作.jquery事件

发表评论

最新留言

很好
[***.229.124.182]2024年04月08日 22时41分30秒