一篇文章带你了解JavaScript中的变量,作用域和内存问题
1
在JavaScript中的变量分别区分为两种:
一种为基本类型值,一种为应用类型值。
基本类型值指的是简单的数据段
引用类型值为可能由多个值组成的对象
引用类型的值是保存在内存中的对象,JavaScript不允许直接操作对象的内存空间,实际上操作对象的引用而不是实际对象。
var dada = new Object();undefineddada.name = "dada";"dada"console.log(dada.name);VM158:1 dadaundefined
var da1 = "da1";undefinedda1.age = 12;12console.log(da1.age);VM272:1 undefinedundefined
基本类型的值添加属性,是不管用的,只能给引用类型的值动态地添加属性,才是有用的。
2
复制变量值
就是从一个变量向另一个变量复制 基本类型值 和 引用类型值
基本类型的值添加属性,是不管用的,只能给引用类型的值动态地添加属性,才是有用的。2复制变量值就是从一个变量向另一个变量复制 基本类型值 和 引用类型值
da1中保存的值是12,使用da1的值来初始化da2时,da2中也保存了值12,但是d2中的值12和da1中的值12是完全独立的。这两个变量可以参与任何操作互不影响。
我自己是一名从事了多年开发的web前端老程序员,目前辞职在做自己的web前端私人定制课程,今年年初我花了一个月整理了一份最适合2019年学习的web前端学习干货,各种框架都有整理,送给每一位前端小伙伴,想要获取的可以关注我并添加我的web前端交流群:600610151,即可免费获取。
从一个变量向另一个变量复制引用类型的值:
引用类型的值实际上是一个指针,是指向存储在堆中的一个对象,引用类型的复制,是将指向引用同一个对象,所以改变其中一个变量,另一个变量也会受到影响。
var da3 = new Object();var da4 = da3;da3.name = "dada";console.log(da4.name);
da3和da4指向同一个对象,da3添加name属性后,da4来访问这个属性,因为两个变量指向同一个对象,所以输出结果为dada。
3
参数传递:
在JavaScript中所有函数的参数都是按值传递的,参数按值传递的意思,和复制一样的,把函数外的值传递到函数内部。
function addNum(num){ num = num + 1; return num;}var da5 = 12;var result = addNum(da5);console.log(da5);console.log(result);
函数addNum有一个参数num,这个参数实际为函数的局部变量。调用这个函数,变量da5作为参数被传递给了这个函数,这个变量的值为12,所以参数num为12在这个addNum()函数中使用。
function setName(obj) { obj.name = "dada";}var da6 = new Object();setName(da6);console.log(da6.name);
检测类型:
typeof操作符是用来检测一个变量是否是基本数据类型,如果变量的值为一个对象或null,那么这个typeof操作符下返回的就是object。
var da7 = "dada";var da8 = 12;var da9;var da10 = null;var da11 = new Object();console.log(typeof da7);console.log(typeof da8);console.log(typeof da9);console.log(typeof da10);console.log(typeof da11);
instanceof操作符,是用来干什么的呢?判断是什么类型的对象。
// 前提先定义personconsole.log(personinstanceof Object);console.log(person instanceof Array);console.log(personinstanceofRegExp);
注意,所有的引用类型的值都是Object的实例,所以检测引用类型的值和Object构造函数时,instanceof操作符都是返回true。instanceof操作符检测基本类型的值,返回的则都是false。因为instanceof检测的都是什么类型的对象。
4
作用域:
当代码在一个环境中执行时,会创建变量对象的一个作用域链,这个作用域链的用途是 保证对执行环境有权访问的多有变量和函数的有序访问。全局执行环境的变量对象都是作用域链中的最后一个对象。
标识符解析是沿着作用域链一级一级地搜索标识符的过程。
var da12 = "dada"function changeDa(){ if(da12 === "dada"){ da12 = "da"; }else{ da12 = "da1"; }}changeDa();console.log(da12);
函数changeDa()的作用域链包含两个对象:
它自己的变量对象,和,全局环境的 变量对象。
它自己的 定义着的arguments对象
var da12 = "dada"function changeDa(){ var anotherDa = "dadada"; function daDa(){ var tempDa = anotherDa; anotherDa = da12; da12 = tempDa; // 可以访问 tempDa, anotherDa,da12 } // 这里只能访问 da12,anotherDa daDa();}// 这里只能访问da12;changeDa();
分析执行环境,有3个,一个为全局环境,一个为changeDa()的局部环境,一个为daDa()的局部环境。
全局环境中有一个变量da12,和一个函数changeDa()。
changeDa()的局部环境中有什么?
一个变量anotherDa,一个名为daDa()的函数。这个函数可以访问全局变量中的da12。
daDa()的局部环境中有什么?
一个变量tempDa,该变量只能在这个环境中访问。
无论是全局环境还是changeDa()的局部环境都无法访问tempDa。
为什么内部的daDa()可以访问其他两个环境中的所有变量呢?
因为那是它们两个的环境是它的父执行环境。
内部环境可以通过作用域链访问所有的外部环境,但是外部环境不能访问内部环境中的任何变量和函数,内部环境都可以向上搜索作用域链,查变量和函数名,不能向下搜索作用域链进入另一个环境。
对于daDa()函数,其中作用域链包含3个对象:
daDa()的变量对象,changeDa()的变量对象,全局变量对象。
过程:
daDa()函数的局部环境,会先开始搜索自己的变量对象中的变量和函数名,如果找不到,会向上搜索上一级的作用域链。
对于changDa()中的环境:
它包含两个对象::一为它自己的变量对象,二为全局变量对象。
即它不能访问daDa()函数的局部环境。
5
执行环境分两种:
一种为全局作用域,一种为局部作用域。
如何理解 try catch 延长了作用域链?
with语句和 try catch 都可以延长作用域链
with比较好理解,而且一般有性能问题,也不推荐用
try catch 是捕获Error对象的时候 会新开一个作用域吗?
还是说 catch的大括号内就是一个能访问到error对象的块级作用域?
try中的代码捕获到错误以后,会把异常对象推入一个可变对象并置于用域的头部,在catch代码块内部,函数的所有局部变量将会被放在第二个作用域对象中,catch中的代码执行完,会立即销毁当前作用域。
什么叫延长作用域链
执行环境(变量对象可谓是它的衍生物)、作用域、作用域链
作用域:函数当前执行环境。
作用域链:执行环境产生的变量对象构成。 作用域链是保证函数在执行时能够正确访问需要的变量和函数。
作用域链最外层就是全局作用域
var i = 0;function dada(){ console.log(i);}undefineddada();VM656:3 0undefine
在函数中是没有存在i的,但是在调用这个函数时会返回为0,这是为什么呢?这就是函数作用域链的作用。
延长一: try catch
(function(window){ try{ throw Error("出错误了"); }catch(e){ alert(e); //alert("Error: 出错误了") } console.log(e); //undefind})(window);
在执行catch语句块时,JavaScript自动把其执行环境添加作用域链中,但是该语句块执行完后又自动把该执行环境(变量对象)移除。
alert(e) == alert("Error:出现错误");console.log(e) == undefined;
IE结果:
alert(e) => alert("Error: 出错误了"); console.log(e) => object Error: 出错误了{description: "出错误了",message: "出错误了",name: "Error"}
延长二:with
function da(){ console.log(location.href); } function da(){ with(location){ console.log(href); } }
两种方式是等价的:
前提是非严格模式下, 因为严格模式下不支持 with这种方式。
延长作用域的表现
什么是作用域链?
我的理解就是,根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问。
想要知道js怎么链式查找,就得先了解js的执行环境。
每个函数运行时都会产生一个执行环境,而这个执行环境怎么表示呢?
js为每一个执行环境关联了一个变量对象。环境中定义的所有变量和函数都保存在这个对象中。
没有块级作用域:
if(true) { var da = "dada";}console.log(da);
function add(num1,num2){ var num = num1 + num2; return num;}undefinedvar result = add(1,2);undefinedconsole.log(result);VM962:1 3undefined
向上查询:
var da = "dada";function getDa(){ var da = "dadada"; return da;}console.log(getDa());
JavaScript中最常用的垃圾收集方式是标记清除,另一种不太常见的垃圾策略叫做引用计数。
基本类型值和引用类型值:
基本类型值在内存中占据固定的空间,保存在栈内存中,从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本,引用类型的值为对象,保存在堆内存中。
包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向对象的指针。
typeof操作符判断的是一个值是哪种基本类型,instanceof操作符判断的是一个值是哪种引用类型。
执行环境分:
全局执行环境,函数执行环境。
每次进入一个新的执行环境时,都会创建一个用于搜索变量和函数的作用域链。
一篇文章带你了解JavaScript中的变量,作用域和内存问题的更多相关文章
- 一篇文章带你了解JavaScript中的语法,数据类型,流程控制语句以及函数
作者 | Jeskson 来源 | 达达前端小酒馆 1 JavaScript有多重要啊,才能让我说说一下,其中的语法,操作符,数据类型,内置功能等. 语法: 在JavaScript中的变量,函数名和操 ...
- JavaScript学习系列2一JavaScript中的变量作用域
在写这篇文章之前,再次提醒一下 JavaScript 是大小写敏感的语言 // 'test', 'Test', 'TeSt' , 'TEST' 是4个不同的变量名 JavaScript中的变量,最重要 ...
- javascript中的变量作用域以及变量提升
在javascript中, 理解变量的作用域以及变量提升是非常有必要的.这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解. 变量作用域 “一个变量的作用域表示这个变量存在的上 ...
- javascript中的变量作用域以及变量提升详细介绍
在javascript中, 理解变量的作用域以及变量提升是非常有必要的.这个看起来是否很简单,但其实并不是你想的那样,还要一些重要的细节你需要理解变量作用域 “一个变量的作用域表示这个变量存在的上下文 ...
- javascript中的变量作用域
在网上看了一道js面试题 <script type="text/javascript"> var tt = 'aa'; function test() { alert( ...
- 一篇文章带你了解网页框架——Vue简单入门
一篇文章带你了解网页框架--Vue简单入门 这篇文章将会介绍我们前端入门级别的框架--Vue的简单使用 如果你以后想从事后端程序员,又想要稍微了解前端框架知识,那么这篇文章或许可以给你带来帮助 温馨提 ...
- MYSQL(基本篇)——一篇文章带你走进MYSQL的奇妙世界
MYSQL(基本篇)--一篇文章带你走进MYSQL的奇妙世界 MYSQL算是我们程序员必不可少的一份求职工具了 无论在什么岗位,我们都可以看到应聘要求上所书写的"精通MYSQL等数据库及优化 ...
- MYSQL(进阶篇)——一篇文章带你深入掌握MYSQL
MYSQL(进阶篇)--一篇文章带你深入掌握MYSQL 我们在上篇文章中已经学习了MYSQL的基本语法和概念 在这篇文章中我们将讲解底层结构和一些新的语法帮助你更好的运用MYSQL 温馨提醒:该文章大 ...
- 一篇文章带你掌握主流数据库框架——MyBatis
一篇文章带你掌握主流数据库框架--MyBatis MyBatis 是一款优秀的持久层框架,它支持自定义 SQL.存储过程以及高级映射. 在之前的文章中我们学习了MYSQL和JDBC,但是这些东西远远不 ...
随机推荐
- 题解【洛谷P2070】刷墙
题面 将每一次移动的距离进行差分,前缀和判断移动的距离是否\(\geq 2\)即可. #include <bits/stdc++.h> #define itn int #define gI ...
- 素问 - 使用 PE、PB 做估值
摘自<小韭的学习圈> Q 哪些行业用PE看合适,哪些用PB看合适啊?其中的大致逻辑是什么? A PE = 股价 / 每股收益 使用PE的逻辑是,我们认为一个股票有价值,是因为公司未来能赚钱 ...
- 自己动手系列----使用数组实现一个简单的Map
数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同.Java 语言中提供的数组是用来存储固定大小的同类型元素. 这里提一下,数组的优缺点: 优点: 1. 使用索 ...
- [HEOI2015] 小Z的房间 - 矩阵树定理
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 105; const i ...
- COMMUNITY DETECTION_python-louvain
Python-louvain Package pip install python-louvain import community #first compute the best partition ...
- ORA-01789: 查询块具有不正确的结果列数
问题描述 ORA-01789: 查询块具有不正确的结果列数 问题原因 sql语句用union时的 两个语句查询的字段不一致,好像顺序也要保持一致才行
- NAND FLASH驱动框架以及程序实现
1.NAND FLASH的硬件连接: 实验用的NAND FLASH芯片为K9F2G08U0C,它是三星公司的存储芯片,它的大小为256M.它的接线图如下所示: 它的每个引脚的分别为LDATA0-LDA ...
- ASP.NET + MVC5 入门完整教程三 (下) ---MVC 松耦合
建立松耦合组件 MVC 模式最重要的特性之一视他支持关注分离,希望应用程序中的组件尽可能独立,只有很少的几个可控依赖项.在理想的情况下,每个组件都不了解其他组件,而只是通过抽象接口来处理应用程序的其他 ...
- 题解【SP1716】GSS3 - Can you answer these queries III
题目描述 You are given a sequence \(A\) of \(N (N <= 50000)\) integers between \(-10000\) and \(10000 ...
- 调用原生硬件 Api 实现照相机 拍照和相册选择 以及拍照上传
一.Flutter image_picker 实现相机拍照和相册选择 https://pub.dev/packages/image_picker 二.Flutter 上传图片到服务器 ht ...