为什么要将这些内容放在一起,因为他们都跟初始化有关系,我们慢慢说吧。

我们在代码中,都会声明变量、函数和对象,然后由浏览器解释器(下面简称浏览器)执行;

我们还说过,变量和对象的内存结构;

那么,是什么时候,我们声明的变量和对象,被浏览器分配内存了呢?

我们使用不同的声明方式,浏览器分配内存的顺序是一样的吗?

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的更多相关文章

  1. javascript变量的作用域

    javascript变量的作用域 基本类型和引用类型 基本类型值指的是简单的数据段,而引用类型值指的是那个可能由多个值组成的对象  讲一个值赋值给变量时,javascript解析器首先要确定是基本类型 ...

  2. javascript 函数初探 (三)--- javascript 变量的作用域

    javascript 变量的作用域: 这是一个至关重要的问题.特别是当我们从别的语言转向javascript时,必须要明白一点,即在javascript中,变量的定义并不是以代码块作为作用域的,而是以 ...

  3. let,const 声明的变量不会绑定给window对象 而var会

    先来看一道题 let id = 2; let json = { id: 1, show:function(){ setTimeout(function(){ console.log(this.id); ...

  4. 深入理解 JavaScript 变量的作用域和作用域链

    一个变量的作用域(scope)是程序源代码中定义这个变量的区域.简单的说,作用域就是变量与函数的可访问范围.全局变量拥有全局作用域,在JavaScript代码中的任何地方都有定义.局部变量是在函数体内 ...

  5. JavaScript变量的作用域和函数的作用域的区别

    变量作用域和函数作用域都涉及到变量值的变化,本文旨在让大家明白他们之间的区别 变量的作用域: 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接 ...

  6. javascript变量、作用域和内存问题......

    1基本类型是指那些保存在栈内存的简单数据段,引用类型是指那些保存在堆内存中的对象,变量中保存的实际上只是一个指针. 2javascript中5种基本数据类型Undefined,Null,Boolean ...

  7. JavaScript 变量、作用域及内存详解

    基本类型值有:undefined,NUll,Boolean,Number和String,这些类型分别在内存中占有固定的大小空间,他们的值保存在栈空间,我们通过按值来访问的. (1)值类型:数值.布尔值 ...

  8. 深入浅出 JavaScript 变量、作用域和内存 v 0.5

    本文主要从原理入手分享变量和作用域的相关知识,最后结合本文所分享知识,再次深入了解下闭包的运行原理. 主要参考<JS高级程序设计> <JS权威指南> <高性能 JS> ...

  9. 【javascript 变量和作用域】

    今天学习了javascript 的变量和作用域的基本知识,对于以前在开发中遇到的一些不懂的小问题也有了系统的认识,收获还是比较多的. [基本类型和引用类型] ECMAScript 变量可能包含两种不同 ...

  10. [从jQuery看JavaScript]-变量与作用域链

    jQuery片段: var // Will speed up references to window, and allows munging its name. window = this, //  ...

随机推荐

  1. Pycharm安装使用

    目录 使用pycharm软件 配置调整 下载链接地址:https://www.jetbrains.com/pycharm/download/#section=windows 根据自己的系统需要安装对应 ...

  2. 在js中正则表达式验证小时分钟,将输入的字符串转换为对应的小时和分钟

    文章目录 1.预备知识 2.在js中的代码片段 3.测试结果 1.预备知识 splict()方法 Date()的相关方法 setHours()的用法 2.在js中的代码片段 //验证小时和分钟 var ...

  3. CentOS 7.9 Related Software Directory

    一.CentOS 7.9 Related Software Directory Installing VMware Workstation Pro on Windows Installing Cent ...

  4. Linux三剑客sed

    注意sed和awk使用单引号,双引号有特殊解释 sed是Stream Editor(字符流编辑器)的缩写,简称流编辑器. sed是操作.过滤和转换文本内容的强大工具. 常用功能包括结合正则表达式对文件 ...

  5. Linux文件属性与管理

    文件或目录属性主要包括: 索引节点,inode 文件类型 文件权限 硬链接个数 归属的用户和用户组 最新修改时间 查看命令 ls -lhi /opt 图解: Inode索引节点号,(人的身份证,家庭地 ...

  6. 【性能测试】Loadrunner12.55(二)-飞机订票系统-脚本录制

    1.1 飞机订票系统 Loadrunner 12.55不会自动安装飞机订票系统,要自己手动安装. 我们需要下载Web Tools以及一个小插件strawberry https://marketplac ...

  7. Programiranje 方法记录

    [COCI2017-2018#3] Programiranje 题面翻译 题目描述 Little Leticija正在准备编程考试.虽然她已经解决了很多任务,但还有一个任务尚未解决,所以她正在向你寻求 ...

  8. Rock18框架之整体框架介绍

    1. 总体框架图 2.框架能解决哪些问题? 问题1: 自动化设备包含龙门架.机械手.伺服.步进等电机.IO控制.定位及纠偏.界面展示等部分.其中硬件(伺服.IO等)是需要更换的,硬件的更换不影响整套系 ...

  9. 树上启发式合并(dsu on tree)

    树上启发式合并属于暴力的优化,复杂度O(nlogn) 主要解决的问题特点在于: 1.对于树上的某些信息进行查询 2.一般问题的解决不包含对树的修改,所有答案可以离线解决 算法思路:这类问题的特点在于父 ...

  10. Spring Boot 中使用 tkMapper

    说明:基于 MyBatis 有很多第三方功能插件,这些插件可以完成数据操作方法的封装.数据库逆向工程的生成等. tkMapper 和 MyBatis-plus 都是基于 MyBatis 提供的第三方插 ...