重新认识一下JS声明变量的六种方式吧

开始

先说一下JS中有哪六种变量的声明方法吧,然后我们带着三个问号去看文章:what?how? where?
六种声明变量的方法:

  1. var
  2. let
  3. const
  4. function
  5. import
  6. class

没有对比就没有伤害(var、let、const)

面试中,有不少的面试官喜欢问let、var、const的区别,虽然这个问题很简单,但是从这道题中,可以看出你的编码习惯和风格;
有的同学表示很疑惑了,从这道题怎么会看出自己的编码习惯和风格呢,那么好,疑问三连送给你:

  1. 你见过全是var变量的JavaScript吗?
  2. 你经历过滥用let的后果吗?
  3. 你知道const的命名规范吗?

下面我们来看一下它们之间的区别 (如果大佬需要补充,请到评论区):

var let const
存在变量提升 不存在变量提升 不存在变量提升
代码块外部可调用 存在块级作用域 存在块级作用域
赋值后值不可改变

通过上面的表格我们可以看到它们之间的大体区别,虽然差别不是很多,但是在实际开发中,却有着大大小小的坑


来看第一段代码(耐心看完下面三段代码,并不难哦):

  function fun(str){
    let str = 'hello'+'world!';
    console.log(str);
  }
  fun('123');

没错,这是一段有问题的代码,运行后是一个语法错误:Uncaught SyntaxError:Identifier 'code' has already been declared,进一步解析一下它运行后的样子:

  function fun(str){
    var str;   // 这个变量代表的是函数形参
    let str = 'hello'+'world!';
    
    // 这时候fun函数的作用域顶部,有两个变量名为str,所以报错!
    console.log(str);
  }
  fun('123')

这也说明了在同一作用域中,任何变量是不可以重复声明的,我就是我,颜色不一样的烟火!

总结:这段代码需要注意的坑:作用域、变量提升、变量名禁止重复;

如果对上面的代码理解了,咱们来看第二段代码:

  var str = 'hello';

  function fun(){
    console.log(str);
    let str = 'world';
    console.log(str);
  }
  fun();

只要块级作用域内存在let命令,它所声明的变量就“绑定”这个区域,不再受外部的影响,这也就是传说中的 暂时性死区,ES6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错,所以上面是一段错误代码:Uncaught ReferenceError: Cannot access 'str' before initialization

总结:这段代码需要注意的坑:暂时性死区、块级作用域

消化完上面代码,继续来看最后一段代码:

  const obj = {};
  let str = '坚持一周写两篇博客';
  let addObj = obj.names = str;
  
  console.log(addObj);

看到这段代码后,有的同学就会说了:你不是说const的值不能改变吗?你个骗子!
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。
const需要注意的点:

  1. 只声明不赋值,就会报错
  2. 只在声明所在的块级作用域内有效
  3. const命令声明的常量也是不提升,同样存在暂时性死区
  4. 不可重复声明
  5. 想将对象冻结,应该使用Object.freeze方法

function、import、class

function

ES6规定:

  • 允许在块级作用域内声明函数。
  • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
  • 同时,函数声明还会提升到所在的块级作用域的头部。

注意,上面三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。

根据这三条规则,浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于var声明的变量。上面的例子实际运行的代码如下:

// 浏览器的 ES6 环境
function f() { console.log('I am outside!'); }
(function () {
  var f = undefined;
  if (false) {
    function f() { console.log('I am inside!'); }
  }

  f();
}());
// Uncaught TypeError: f is not a function

import

import用于加载文件,在大括号接收的是一个或多个变量名,这些变量名需要与你想要导入的变量名相同。

举个栗子:你想要导入action.js文件中的某一个变量,这个变量里保存了一段代码块,所以你要写成:import { Button } from 'action',这个时候,你就从action.js中获取到了一个叫 Button 的变量,既然获取到了,你就可以对Button里的代码猥琐欲为了

如果想为输入的变量重新取一个名字,import命令要使用as关键字,将输入的变量重命名,比如:

import { NewButton as Button } from 'action.js';

上面的代码表示从action.js文件中,获取一个变量名称叫做Button的代码段,然后你又声明了一个变量 NewButton ,将 Button 保存在 NewButton


class

关于class,后期我会单独写一篇文章,详细的介绍一下,这里就简单说一下:
首先通过看ES5中的构造函数,然后再用ES6的class去实现:

// ES5写法 :
  function fun ( x, y ){
    this.x = x;
    this.y = y;
  };

  fun.prototype.GetHair = function(){
    return `${this.x}掉了两根头发,${this.y}说俺也一样!`;
  };

  let setHair = new fun('小明','老王');
  console.log(setHair.GetHair()); // 小明掉了两根头发,老王说俺也一样!

再来看一下ES6的class写法:

  class interest {

    constructor( x, y, e, z ){
      this.x = x;
      this.y = y;
      this.e = e;
      this.z = z;
    }

    MyInterest(){
      let arr = [];
      console.log(`我会${[...arr,this.x,this.y,this.e,this.z]}!`);
    }
  }

  let GetInterest = new interest('唱','跳','rap','篮球');
  console.log(GetInterest.MyInterest());  //我会唱,跳,rap,篮球!

ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已,constructor方法就是构造方法,而this关键字则代表实例对象。也就是ES5 的构造函数Point,对应 ES6 的Point类的构造方法。

结束

关于JS声明变量的六种方式就介绍完了,如果对你有帮助的话,就点个赞鼓励一下吧;
文章内容如有不同意见,欢迎评论区指出(初写文章,请多指教)~
本人微信:
wx.jpg

Image placeholder
zengjie
未设置
  26人点赞

没有讨论,发表一下自己的看法吧

推荐文章
《Go语言程序设计》读书笔记(六) 基于共享变量的并发

竞争条件 在一个线性(就是说只有一个goroutine的)的程序中,程序的执行顺序只由程序的逻辑来决定。在有两个或更多goroutine的程序中,每一个goroutine内的语句也是按照既定的顺序去执

ES6系列之变量的解构赋值

1.什么是解构?ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。它在语法上比ES5所提供的更加简洁、紧凑、清晰。它不仅能减少你的代码量,还能从根本上改变你的编码方式。2.数

Bash技巧:使用参数扩展获取变量的子字符串和字符串长度

在bash中,通常使用${parameter}表达式来获取parameter变量的值,这是一种参数扩展(parameterexpansion)。Bash还提供了其他形式的参数扩展,可以对变量值做一些处

程序员有话说:开发人员提升自己的四种方式

开发人员之间所谓的不同“级别”的界线是模糊 的。如果你问高级开发人员、开发经理或技术总监:“初学者、初级、中级和高级之间的区别是什么?”那么很有可能他们会给你截然不同的意见。由于存在各种各样的意见,因

滴滴 曾奇:谈谈我所认识的分布式锁

桔妹导读:随着计算机技术和工程架构的发展,微服务变得越来越热。如今,绝大多数服务都处于分布式环境中,其中,数据一致性是我们一直关注的重点。分布式锁到底是什么?经过了哪些发展演进?工程上有哪些实现方案?

华为“鸿蒙”所涉及的微内核到底是什么?一文带你认识微内核

微内核最近微内核的概念常常被大家提及,同时还有GoogleFuchisa这样的微内核新星,这里让我们一起来认识下微内核吧。背景庞大的UNIX家族计算机技术在二战后快速发展,构成计算机的主要基本单元从电

时区信息记录表|全方位认识 mysql 系统库

在上一期《优化器成本记录表|全方位认识mysql系统库》中,我们详细介绍了mysql系统库中的优化器成本记录表,本期我们将为大家带来系列第六篇《时区信息记录表|全方位认识mysql系统库》,下面请跟随

Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?

在逛StackOverflow的时候,发现了一些访问量像阿尔卑斯山一样高的问题,比如说这个:Java到底是值传递还是引用传递?访问量足足有188万+,这不得了啊!说明有很多很多的程序员被这个问题困扰过

云服务已占企业网络流量的85%

来自云安全公司Netskope的一份报告显示,云服务目前已占企业网络流量的85%。云服务落地加快,主要由跨组织的协作驱动,需要多个云服务来支撑。在前20个云服务中,云存储和协作应用占据了榜单首位,一些

Stack Overflow 上 370万浏览量的一个问题:如何比较 Java 的字符串?

在逛StackOverflow的时候,发现了一些访问量像喜马拉雅山一样高的问题,比如说这个:如何比较Java的字符串?访问量足足有370万+,这不得了啊!说明有很多很多的程序员被这个问题困扰过。PS:

1000亿文本信息,高并发MD5查询,这么大数据量的业务怎么弄?

==提问== 沈老师,你好,想请教一个身份证信息检索的问题。公司有一个每秒5万并发查询的业务,(假设)根据身份证MD5查询身份证信息,目前有1000亿条数据,纯文本存储,前几天看你写LevelDB,请

日均5亿查询量的京东订单中心,为什么舍MySQL用ES?

京东到家订单中心系统业务中,无论是外部商家的订单生产,或是内部上下游系统的依赖,订单查询的调用量都非常大,造成了订单数据读多写少的情况。我们把订单数据存储在MySQL中,但显然只通过DB来支撑大量的查

SQL优化案例-定位系统中大量的rollback(十八)

系统中logfilesync比较严重,查看存储都没有问题,logfileparallelwrite很低,时间分布直方图也没问题数据库中提交和回滚操作比较频繁,每秒1000多次,rollback占比1/

万万没想到,HashMap默认容量的选择,竟然背后有这么多思考!?

集合是Java开发日常开发中经常会使用到的,而作为一种典型的K-V结构的数据结构,HashMap对于Java开发者一定不陌生。在日常开发中,我们经常会像如下方式以下创建一个HashMap:Map ma

Linux 中删除目录的多种方法

有几种不同的方法可以删除 Linux 系统中的目录。如果您使用桌面文件管理器(如Gnome的文件管理器或KDE的Dolphin),则可以使用管理器的图形用户界面删除文件和目录。但是,如果您正在使用无头

CSS实现自适应分隔线的N种方法

分割线是网页中比较常见的一类设计了,比如说知乎的更多回答这里的自适应是指两边的横线会随着文字的个数和父级的宽度自适应偷偷的看了一下知乎的实现,很显然是用一块白色背景覆盖的,加一点背景就露馅了心想:知乎

重新定义数据基础设施,华为的底气与转变

摘要:重新定义,制定新规则,意味着变革,它能让我们在深度思考和发散思维之间寻找更好的解决方案。重新定义存储架构,重新定义数据处理平台,重新定义数据基础设施,今年,华为在数据基础设施领域有点忙。华为何要

Testin用iTestin开启下一代测试,测试行业为什么要“重新来过”?

测试,其实并不是一个新话题。从有软件开发开始,就有测试,最早的测试就是找Bug。后来,自动化测试、云测试、众包测试的模式开始成为流行趋势,今天又迎来以智能化为核心的下一代测试。但是,“测试”从简单的软

“数据+智能” 华为重新定义数据基础设施

互联网的发展,促成了网络订餐平台的崛起,数据的力量正在给传统的餐饮行业带来新的增长。业务场景不断丰富、数据规模越来越大,这对数据采集提出了非常高的要求;出行软件最核心的业务是一个实时在线服务,因此具有

JSON.parse和JSON.stringify的巧用

JSON.parse和JSON.stringify是对json数据的转换,在js中使用的频率还是非常高的,比如localStorage,cookie中对复合型数据的存储,与服务器进行数据交互的格式转换

JSON.parse和JSON.stringify的巧用

JSON.stringify()是将一个JavaScript值(对象或者数组)转换为一个json字符串,如果指定了replacer是一个函数,则可以选择性地替换值,或者如果指定了replacer是一个

JavaScript 变量提升(Hoisting)

'提升'是每个JS开发人员都听说过的一个术语,如果你刚接触JS,可能会遇到一些“怪异”的行为,其中某些变量是随机undefined,会抛出ReferenceErrors异常等等。Hoisting通常被

jquery变量加$和不加$的区别?

jquery变量加$和不加$的区别?加$和不加$没有区别,因为它们都是jquery变量。一般在给jquery对象取名的时候在前面加$。一看就知道是jquery对象。变量命名规则中起始字符可以是:●字母

Bash技巧:详解用$获取变量值是否要加双引号或者大括号

本篇文章介绍在Linuxbashshell中,用$获取变量值时,是否要加双引号、是否要加大括号。用$获取变量值是否要加双引号在bashshell脚本中,用$来获取变量值时,有一些不加双引号,例如$ar

Kotlin如何安全访问lateinit变量

Kotlin设计之初就是不允许非null变量在声明期间不进行初始化的,为了解决这个问题,Kotlinlateinit允许我们先声明一个变量,然后在程序执行周期的将来某个时候将其初始化,让编译检查时不会