JavaScript 的变量与其他语言的变量有很大区别。JavaScript 变量是松散型的(不强制类型)本质。变量的值及其数据类型可以在脚本的生命周期内改 变。
强制类型 如数字型,一旦声明不能改变

1. 变量及作用域

1) 基本类型和引用类型的值

ECMAScript 变量可能包含两种不同的数据类型的值:基本类型值和引用类型值 。

基本类型值 指的是那些保存在栈内存中 的简单数据段,即这种值完全保存在内存中的一个位置。

引用类型值则是指那些保存在堆内存中的对象,意思是变量中保存的实际上只是一个指针,这个指针指向内存中的另一个位置,该位置保存对象。

基本类型值有以下几种:Undefined、Null、Boolean、Number 和 String。这些类型在内存中分别占有固定大小的空间,他们的值保存在栈空间,我们通过按值来访问的。

Null类型只有一个值null,表示一个空对象指针,正式使用typeof操作符检测null会返回object

PS:在某些语言中,字符串以对象的形式来表示,因此被认为是引用类型。ECMAScript放弃这一传统。

如果赋值的是引用类型的值,则必须在堆内存中为这个值分配空间。由于这种值的大小不固定,因此不能把它们保存到栈内存中。但内存地址大小的固定的,因此可以将内存地址保存在栈内存中。
这样,当查询引用类型的变量时,先从栈中读取内存地址,然后再通过地址找到堆中的值。对于这种,我们把它叫做按引用访问。

即所有的类型 栈内存 中都保存数据,只不过基本数据类型保存的是值,而引用数据类型因为值的大小不固定,所以栈内存中保存的是内存地址,在堆内存中保存的值

2)动态属性(数据类型的操作)

定义基本类型值和引用类型值的方式是相似的:创建一个变量并为该变量赋值。但是,当 这个值保存到变量中以后,对不同类型值可以执行的操作则大相径庭。

 var box=new Object();       //创建引用类型box.name='Lee';              //新增一个属性alert(box.name);            //Lee 输出如果是基本类型的值添加属性的话,就会出现问题了。var box='Lee';               //创建一个基本类型box.age=27;              //给基本类型添加属性alert(box.age);          //undefined
ps1:基本类型不能添加属性

3) 复制变量值

在变量复制方面,基本类型和引用类型也有所不同。基本类型复制的是值本身,而引用类型复制的是地址。

 var box='Lee';       //在栈内存生成一个 box  'Lee'var box2=box;       //在栈内存再生成一个 box2 'Lee'console.log(box2)   //Lee box2=3;              //3

ps2:在基本类型中,box2 是虽然是 box1 的一个副本,但从图示可以看出,它是完全独立的。也就是说,基本类型保持不变,两个变量分别操作时互不影响
 var box=new Object();       //创建一个引用类型box.name='Lee';                //新增一个属性var box2=box;                 //"Lee" 把引用地址赋值给 box2box2.name=123;              //123console.log(box.name)      //123

ps3:在引用类型中,box2 其实就是 box,因为他们指向的是同一个对象。如果这个对象中的name 属性被修改了,box2.name 和 box.name 输出的值都会被相应修改掉了。

4) 传递参数

ECMAScript 中所有函数的参数都是按值传递的,言下之意就是说,参数不会按引用传递,虽然变量有基本类型和引用类型之分。

 function box(num){            //按值传递num+=10;               //这里的 num 是局部变量,全局无效return num;}var num=50;alert(box(num));             //60alert(num);                 //50
PS4:以上的代码中,传递的参数是一个基本类型的值。而函数里的 num 是一个局部变量,和外面的 num 没有任何联系。
如果说按引用类型传递,呢么函数里的num会成为类似于全局变量,把外面的num替代。即alert(num) //60

function box(obj){              //这里将要传递一个引用类型的参数,但不是按引用传递,是按值传递的obj.name='wei';var obj=new Object();         //函数内部又创建了一个对象obj.name='Mr.';            //并没有替换掉原来的 obj,依然是局部吧变量//所以,js没有按引用传参的功能,切记,不能把传递引用参数当做按引用传参
}
var p=new Object();
box(p);
alert(p.name);                  //"wei"
PS5:如果存在按引用传递的话,那么函数里的那个变量将会是全局变量,在外部也可以访问。比如 PHP 中,必须在参数前面加上&符号表示按引用传递。而 ECMAScript 没有这些,只能是局部变量。可以在 PHP 中了解一下。
PS6:所以按引用传递和传递引用类型是两个不同的概念。

5) 检测类型

要检测一个变量的类型,我们可以通过 typeof 运算符来判别。诸如:

     var box='Lee';alert(typeof box); //string

虽然 typeof 运算符在检查基本数据类型的时候非常好用,但检测引用类型的时候,它就不是那么好用了。通常,我们并不想知道它是不是对象,而是想知道它到底是什么类型的对象。因为数组也是 object,null 也是 Object 等等。

这时我们应该采用 instanceof 运算符来查看。
 //检测引用类型var box=[1,2,3];alert(box instanceof Array); //true,是否是数组//检查基本数据类型var box4="wei";alert(box4 instanceof String); //false;是否是字符串对象var box4=new String('Lee');alert(box4 instanceof String); //true;是否是字符串对象
PS7:当使用 instanceof 检查基本类型的值时,它会返回 false。必须用new出来

6) 执行环境及作用域

执行环境是 JavaScript 中最为重要的一个概念。执行环境定义了变量或函数有权访问 的其他数据,决定了它们各自的行为。

全局执行环境是最外围的执行环境。在 Web浏览器中,全局执行环境被认为是 window对象。因此所有的全局变量和函数都是作为 window 对象的属性和方法创建的。

 var box='blue';           //声明一个全局变量function setBox(){alert(box);            //全局变量可以在函数里访问}setBox();                    //执行函数全局的变量和函数,都是 window 对象的属性和方法。var box='blue';function setBox(){alert(window.box);      //全局变量即 window 的属性}window.setBox();         //全局函数即 window 的方法
PS8:当执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和 函数定义也随之销毁。如果是全局环境下,需要程序执行完毕,或者网页被关闭才会销毁。

函数里的局部作用域里的变量替换全局变量,但作用域仅限在函数体内这个局部环境。

 var box='blue';function setBox(){var box='red';    //这里是局部变量,出来就不认识了alert(box);}setBox();          //redalert(box);            //blue

通过传参,可以替换函数体内的局部变量,但作用域仅限在函数体内这个局部环境。

var box='blue';
function setBox(box){ //通过传参,替换了全局变量
alert(box);
}
setBox('red');        //red
alert(box);         //blue

函数体内还包含着函数,只有这个函数才可以访问内一层的函数。

 var box='blue';function setBox(){var a="red"function setColor(){  //setcolor()方法作用域在setbox()中,因此在最外面无法调用var b='orange';       //b的作用域在setcolor()中;只能在这个函数内调用alert(box);         //blue,函数无论嵌套几层,都能调用全局变量alert(a);         //redalert(b);          //orgin}setColor();           //setColor()的执行环境在 setBox()内 }setBox();

PS9:当代码在一个环境中执行时,就会形成一种叫做作用域链的东西。它的用途是保证对执行环境中有访问权限的变量和函数进行有序访问。作用域链的前端,就是执行环境的变量对象。

7) 没有块级作用域

块级作用域表示诸如 if 语句等有花括号封闭的代码块,所以,支持条件判断来定义变 量。

if循环语句

 if(true){                    //if 语句代码块没有局部作用域var box='Lee';}alert(box);

for 循环语句也是如此

for(var i=0;i<10;i++){         //没有局部作用域var box='wei';}alert(i);                    //10alert(box);                 //wei

PS:非常不建议不使用 var 就初始化变量(函数内如果去掉 var 就是全局变量了),因为这种方法会导致各种意外发生。所以初始化变量的时候一定要加上 var。
一般确定变量都是通过搜索来确定该标识符实际代表什么。

 var box='blue';function getBox(){return box;          //代表全局 box}                     //如果函数体内加上 var box='red'alert(getBox());     //那么最后返回值就是 red

PS:变量查询中,访问局部变量要比全局变量更快,因为不需要向上搜索作用域链。

javascript 变量及作用域(栈、堆、块级作用域、执行环境)详细篇相关推荐

  1. 详解var、let、const关键词声明变量的区别,以及变量提升、块级作用域的认识等。

    首先回顾一下JavaScript中var声明变量的基础知识: • 在使用var关键词声明变量时,变量在函数外则是全局变量,有全局作用域,全局变量在页面关闭后销毁:变量在函数内则是局部变量,作用局部作用 ...

  2. es6 ie不兼容 函数_ES6:什么是块级作用域?

    在 ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景. 我们先来看一下下面这种情况:内层变量可能会覆盖外层变量. var txt = '外层变量-->你好呀';func ...

  3. 块级作用域和函数作用域

    函数作用域与块级作用域 函数作用域:在函数内部声明的变量只能影响到变量所在函数体本身,无法从外部对函数内部的变量进行调用,被称为'函数作用域' 块级作用域:ES6 引入了 let 和 const 关键 ...

  4. ES6 块级作用域详解

    什么是块级作用域 ES6 中新增了块级作用域.块作用域由 { } 包括,if 语句和 for 语句里面的 { } 也属于块作用域. 为什么需要块级作用域 第一种场景:内部变量会覆盖外部变量 var t ...

  5. 搭建Babel运行环境,Traceur ES6模板,块级作用域,let和const命令

    搭建Babel运行环境 Babel(http://babeljs.io/)可用于将使用ES6语法的脚本转化为ES5语法的脚本,基本功能的安装步骤如下: 1.安装node解释器和npm包管理工具 2.安 ...

  6. ES6基础2(块级作用域、数组对象解构)-学习笔记

    文章目录 ES6基础2(块级作用域.数组对象解构)-学习笔记 块级作用域 数组解构 对象解构 字符串解构 函数的参数解构 ES6基础2(块级作用域.数组对象解构)-学习笔记 块级作用域 //let c ...

  7. java区块作用域_ES6-let、const和块级作用域

    1.介绍 总的来说,ES6是在ES2015的基础上改变了一些书写方式,开放了更多API,这样做的目的最终还是为了贴合实际开发的需要.如果说一门编程语言的诞生是天才的构思和实现,那它的发展无疑就是不断填 ...

  8. js模仿块级作用域(js没有块级作用域私有作用域)

    js模仿块级作用域(js没有块级作用域私有作用域) 一.总结 1.js没有块级作用域:在for循环中定义的i,出了for循环还是有这个i变量 2.js可以模拟块级作用域:用立即执行的匿名函数:(匿名函 ...

  9. let、const和var的区别(涉及块级作用域)

    let .const和var的区别 let.const.var在js中都是用于声明变量的,在没有进行ES6的学习前,我基本只会使用到var关键字进行变量的声明,但在了解了ES6之后就涉及到了块级作用域 ...

  10. 拦截器获取不到sesssion作用域的值_ES6--块级作用域

    本文是一篇读书笔记,来自http://es6.ruanyifeng.com/#docs/let 1.let 只在所在代码块有效 {let a = 10;var b = 1; }a // Referen ...

最新文章

  1. C++为什么空格无法输出_数据的输入输出举例
  2. 飞桨博士会第三期来啦!中国深度学习技术俱乐部诚邀您加入
  3. 低价电阻箱-阻值测试
  4. pybind11传输文件
  5. 【计算机网络】传输层 : TCP 可靠传输 ( 可靠传输机制 | 快速重传机制 )
  6. 复旦大学张奇组:对话摘要数据不足?对话数据、文档摘要数据,我全都要!...
  7. 3.通道 Channel
  8. 盒子模型,top和margin-top
  9. Intel 11代全新核显出现了!好强 好乱
  10. 设计模式之——单例模式
  11. php mysql 内存表_用mysql内存表来代替php session的类_PHP教程
  12. 服务器迁移中心 SMC 最佳实践及新特性介绍
  13. 将url编码数据转换为简单字符串
  14. 网络攻防“三剑客”正式加盟墨者安全 担任首席安全顾问...
  15. 财报解读:硬件支撑思科增长,云平台何时能突围?
  16. mysql笔试题一:查询where having 以及统计函数的使用
  17. 【题解】1118 Birds in Forest (25分)⭐⭐ 【并查集】
  18. 母亲节快乐flash动画素材
  19. C#EmguCV人脸识别技术的实现
  20. 雄迈云台摄像机开箱评测:科技感+个性外观,彰显智能生活品质

热门文章

  1. java的IO操作之--RandomAccessFile
  2. 算法面试:精选微软经典的算法面试100题(第21-25题)
  3. 计算机酒店管理论文摘要,酒店餐饮管理系统论文摘要目录.doc
  4. python用pandas读取数据时出现错误_Python Pandas错误标记数据
  5. python调用百度地图画轨迹图_利用python和百度地图API实现数据地图标注的方法
  6. 2021年3月计算机语言排名,2021年3月编程语言排行榜:TOIBE将迎来重大改变,SQL如愿挤进前十...
  7. android提交sql语句,Android实现创建或升级数据库时执行语句
  8. esp32 python开发环境搭建_ESP32:搭建Ubuntu开发环境
  9. 1、matplotlib绘制一个简单的图形
  10. pytorch RuntimeError: expected scalar type Double but found Float