JavaScript 基础知识(二) 变量-作用域-内存问题、JavaScript引用类型(Object类型、Array类型、Function类型等)等

参考JavaScript 基础知识(一) 嘻


 

一、变量-作用域-内存问题

1.1、基本类型 和 引用类型 的值

  1. 基本类型:指简单的数据段, 保存的变量中的 实际的 值
  2. 引用类型 :指可能由多个值构成的对象,保存在 内存中 的对象; 因此引用类型的值, 当复制保存对象的某个变量时,操作的是对象的 引用 ; 但在为对象添加属性时,操作的是 实际的对象 

 

1.1.1、 动态的属性

定义 基本类型值    引用类型值 的方式类似:  创建变量、 为该变量赋值

注: 只能给 引用类型值 动态添加属性

 

1.1.2、复制变量值

基本类型: 

从一个变量 向 另一个比变量 复制基本类型的值,    会在变量对象 上创建 一个新值,   

然后把该值 复制的到为新变量分配的位置上。(复制后 两个变量值 对应的 5 是完全独立的)

 


引用类型:

 从一个变量 向 另一个比变量 复制引用类型的值,    同样会将存储的变量对象中的值 复制一份 到新变量分配的空间中。  不同的是, 这个值的副本其实是一个 指针,而这个指针 指向存储在 堆中的一个对象

 

 

1.1.3、传递参数

ECMAScript 中所有函数的参数都是按 值 传递的

基本类型:

 


引用类型:

 

 

1.1.4、检测类型

检测基本类型:

 


检测引用类型:

 

 

1.2、执行环境 及 作用域

执行环境(execution context, 简称 “环境”):  

  • 是 JavaScript 中重要的一个概念。执行环境定义了变量 或 函数 有权访问的其他数据,决定了它们各自的行为。
  • 每个执行环境 都有一个与之关联的 变量对象, 环境中定义的所有变量和函数都保存在这个对象中。(Web浏览器中, 全局执行环境是 window 对象, 之后详解 )

 

每个函数都有自己的 执行环境(当执行流进入一个函数时,函数的环境就被推入一个环境栈中。     而在函数执行之后,栈将环境弹出, 把控制权返回给之前的执行环境。)

 

当代码在一个环境中执行时,会创建变量对象的一个 作用域链

作用域链的用途:  保证对执行环境有权访问的所有变量 和 函数的 有序访问。

 

  1. 作用域链的前端, 始终是当前执行的代码所在环境的 变量对象
  2. 如果这个环境是函数, 则将其活动对象 作为 变量对象。 活动对象在最开始时只包含一个变量, 即 arguments 对象(此对象在全局环境中是不存在的)。 
  3. 作用域链中的下一个变量来自包含 (外部)环境, 而再下一个对象则来自下一个包含环境。就这样一直延续到全局执行环境; 全局执行环境的变量对象始终都是作用域链中的最后一个对象

 

 


对于 swapColor() 环境而言, 包含三个 对象:

swapColor()的变量对象、 changeColor() 的变量对象 和 全局变量对象。

(搜索变量或函数时, 会先在直接的环境中搜索, 若搜不到 再搜索上一级作用域链。)

 

小结:

  • 内部环境 可以通过作用域链 访问所有的外部环境;  但外部环境 不能访问内部环境 中的任何变量和函数;
  • 环境直接的联系是 线性、有次序的;
  • 每个环境都可以向上搜索作用域链, 以查询变量和函数名; 但 任何环境 都不能通过 向下 搜索作用域链 而进入另一个执行环境。

 

 

1.2.1、延长作用域链

方法:

try - catch 语句的 catch 块: 会创建一个新的变量对象,其中包含的时被抛出的错误对象的声明;

with 语句(不推荐使用):将指定的对象 添加到 作用域链中。

 

 

1.2.2、没有块级作用域       

JavaScript 没有 块级作用域经常会导致理解上的困惑。  在其他类 Java 的语言中,由花括号封闭的代码块都有自己的作用域(如果用ECMAScript的话来讲,就是它们自己的执行环境), 因而支持根据条件来定义变量

 

如下图:

这里是在一个 if 语句中定义了变量 color 。 如果是在C、C++或Java中, color会在if语句执行完毕后被销毁。但在JavaScript中, if 语句中的变量声明会将变量添加到当前的执行环境(在这里是全局环境)中。

 

对于有块级作用域的语言来说(如 Java),for 语句初始化变量的表达式所定义的变量,只会存在于循环的环境之中

 

【牢记!! ! 】而对于JavaScript来说,由 for 语句创建的变量 i 即使在for循环执行结束后,也依旧会存在于循环外部的执行环境中。 

  

 

声明变量:

  • 使用 var 声明的变量会自动被添加到最接近的环境中
  • 在函数内部,最接近的环境就是函数的局部环境;  在with语句中,最接近的环境是函数环境。
  • 如果初始化变量时没有使用var声明,该变量会自动被添加到全局环境

 

查询标识符:

  1. 当在某个环境中为T读取或写入而引用一个标识符时, 必须通过搜索来确定该标识符实际代表什么。
  2. 搜索过程从作用域链的前端开始,向上逐级查询与给定名字匹配的标识符。
  3. 如果在局部环境中找到了该标识符,搜索过程停止,变量就绪。
  4. 如果在局部环境中没有找到该变量名,则继续沿作用域链向上搜索。
  5. 搜索过程将一直追溯到全局环境的变量对象。
  6. 如果在全局环境中也没有找到这个标识符,则意味着该变量尚未声明

在这个搜索过程中,如果存在一个局部的变量的定义,则搜索会自动停止,不再进入另一个变量对象。

即如果局部环境中存在着同名标识符,就不会使用位于父环境中的标识符

 


【区别】

即任何位于局部变量 color 的通过 var 声明之后的代码,    如果不使用window.color都无法访问全局color变量。

 

 

1.3、垃圾收集

JavaScript 具有自动垃圾收集机制,即 执行环境会负责管理代码执行过程中使用的内存。

原理:

找出那些不再继续使用的变量, 然后释放内存。

 

1.3.1、标记清除

JavaScript  最常用的垃圾收集方式是标记清除

原理:

 垃圾收集器在运行的时候会给存储在内存中的所有变量加上标记(当然,可以使用任何标记方式)然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。

而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。

最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间
 

 

1.3.2、引用计数

不太常见的垃圾收集策略叫做引用计数( eferenee counting), 引用计数的含义是跟踪记录每个值被引用的次数。

此方法,容易导致循环引用的情况,从而出现内存泄漏现象。(如 element等DOM元素 和 Object 等类型数据,互相引用, element.someObject=  object ; object.someProp =element )

 

1.3.3、性能问题

 垃圾收集器是周期性运行的,而且如果为变量分配的内存数量很可观,那么回收工作量也是相当大的。

 

1.3.4、管理内存

使用具备垃圾收集机制的语言编写程序,开发人员一般不必操心内存管理的问题。

 但是,JavaScript  在进行内存管理及垃圾收集时面临的问题还是有点与众不同。

其中最主要的一个问题, 就是分配给Web浏览器的可用内存数量通常要比分配给桌面应用程序的少

这样做的目的主要是出于安全方面的考虑,目的是防止运行JavaScript的网页耗尽全部系统内存而导致系统崩溃。

内存限制问题不仅会影响给变量分配内存,同时还会影响调用栈以及在一个线 程中能够同时执行的语句数量。
 


因此,确保占用最少的内存可以让页面获得更好的性能。

而优化内存古用的最佳方式,就是为执行中的代码只保存必要的数据

一旦数据不再有用,最好通过将其值设置为 null 来释放其引用——此做法叫 解除引用

不过,解除一个值的引用并不意味着自动回收该值所占用的内存 。

解除引用真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。
 

 

1.4、小结

 JavaScript 变量可以用来保存两种类型的值:

基本类型值 和 引用类型值;

 

基本类型的值源自以下 6 种基本数据类型:

Undefined、 Null、 Boolean、 Number 、String和 symbol;

 

基本类型值和引用类型值具有以下特点

  • 基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中;
  • 从个变量向另-个变量 复制 基本类型的值,会创建这个值的一个副本
  • 引用类型的值是对象,保存在堆内存中
  • 包含引用类型值的变量实际上包含的并不是对象本身,而是个指向该对象的指针;
  • 从一个变量向另一个变量 复制 引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象;
  • 确定一个值是哪种引用类型可以使用 typeof 操作符, 而确定一个值是哪种引用类型可以使用 instanceof 操作符。

 


所有变量(包括基本类型和引用类型)都在于一个执行环境(也称为作用域)当中,    这个执行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量。 

以下是执行环境的几点总结:

  • 执行环境有全局执行环境(也称为全局环境)  和 函数执行环境之分;
  • 每次进人一个新执行环境,都会创建用于搜索变量 和 函数的作用域链
  • 函数的局部环境不仅有权访问的函数作用城中的变量,而且有权访问其包含(父)环境,乃至全局环境
  • 全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据;
  • 变量的执行环境有助于确定应该何时释放内存。

 


JavaScript  具有自动垃圾收集机制的编程语言, 开发人员不必关心内存分配和回收问题。

  • 可以对JavaScript 的垃圾收集例程作如下总结:
  • 离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除;
  • 标记清除”是目前主流的垃圾收集算法,这种算法的思想是给当前不使用的值加上标记,然后再回收其内存
  • 另种垃圾收集算法 是"引用计数,这种算法的思想是跟踪记录所有值被引用的次数。JavaScript引擎目前都不再使用这种算法,但在IE中访问非原生JavaScript对象(如DOM元素)时,这种算法仍然可能会导致问题。
  • 当代码中存在循环引用现象时,“引用计数”算法就会导致问题
  • 解除变量的引用不仅有助消除循环引用现象,而且对垃圾收集也有好处,为了确保有效地回收内存,应该及时解除不再使用的全局对象、全局对象属性以及循环引用变量的引用。

 

 


二、JavaScript引用类型(Object类型、Array类型、Function类型等)等

2.1、引用类型  Object类型

创建方式:

1、 使用 new 操作符后跟 Object 构造函数:  var person = new Object();  person.age = 12;

2、使用 对象字面量 表示法(常用): var person = { "age" : 12 }  

 

 

2.2、引用类型  Array类型     

ECMAScript 数组的大小可以动态调整,即可以随着数据的添加自动增长以容纳新增数据。

 

创建方式(数组最多可以包含  4 294 967 295 个项):

1、使用 Array 构造函数var colors = new Array();                  var colors2 = new Array(20); // 设置数组长度为20   

                                          var colors3 = Array(3); // 省略new关键字   var color4 = Array('Tom'); // 包含一项

                                            

 


2、使用 数组字面量 表示法:var colors = ["red", "blue", "yellow"]

              

 

2.2.1、 检测数组 : instanceof、 Array.isArray()

 

2.2.2、转换方法: toLocaleString() 、 toString()、 valueOf()

 

2.2.3、栈方法:栈是一种 LIFO(Last-In-First-Out,后进先出)的数据结构,即最新添加的项最早被移除。

 

2.2.4、队列方法: 队列是一种 FIFO(First-In-First-Out,先进先出)的数据结构,即队列在列表末端添加项, 从列表的前端移除项。

 

2.2.5、重排序方法: reverse() 、 sort()

 

2.2.6、操作方法: concat()、 slice()、splice()

 

2.2.7、位置方法: indexOf()、 lastIndexOf()

 

2.2.8、迭代方法: every()、 filter()、forEach() 、map() 、some() ;

  • 以上五个方法 都包含三个参数: 数组项的值、该项在数组中的位置 和 数组对象本身
  • 以上五个方法 都不会改变 原数组中 包含的值;

 

 

2.2.9、归并方法:reduce() 、reduceRight() ;

  • reduce() 从数组的第一项开始,逐个遍历到最后;
  • reduceRight() 从数组的最后一项开始,向前逐个遍历;
  • 这两个方法都会迭代数组的所有项, 然后构建一个最终返回的值;
  • 这两个方法接收的两个参数: 在每一项上调用的函数(前一个值、当前值、项的索引和数组对象;函数返回值作为第一个参数自动传给下一项) 和  作为归并基础的初始值

 

2.3、引用类型  Date类型       

创建日期对象:  var date = new Date();

 

Date.parse()  接收表示日期的字符串参数

Date.UTC()  参数分别是: 年份、基于0的月份(一月是0,二月是1...)、月中的哪一天(1 到 31)、小时数(0 到 23)、分钟、秒 以及 毫秒数。

 

2.3.1、继承的方法

 

2.3.2、日期格式化方法

 

2.3.3、日期/时间组件方法,详细参考这里

 

2.4、引用类型  RegExp类型,参考这里

 

2.5、引用类型  Function类型    

函数是对象,函数名是指针

 

2.5.1、没有重载!!!

 

2.5.2、函数声明 和 函数表达式

 

2.5.3、作为值的函数: 将函数作为参数传递给另一个函数将一个函数作为另一个函数的结果返回

 

2.5.4、函数内部属性

  • 两个特殊的对象: arguments  和 this
  • argumenus.callee 属性是一个指针, 指向拥有argumenus 对象的函数;
  • 函数名.caller 属性保持着调用当前函数的 函数的引用;
  • this 引用的是函数执行的环境对象 (如当网页的全局作用域中调用函数时, this 对象引用的就是 window);

 

2.5.5、函数的属性和方法

两个属性: length prototype

每个函数都包含以下方法:

  • apply():两个参数,在其中运行函数的作用域、参数数组(Array的实例、arguments 对象);
  • call():参数一是在其中运行函数的作用域、其余参数直接传递给函数;
  • bind():IE9+以上浏览器可见,此方法会创建一个函数实例,其 this 值会被绑定到传给 bind() 函数的值;

 

2.6、引用类型  基本包装类型     

3 种特殊引用类型: Boolean、Number 和 String

引用类型 和 基本包装类型的主要区别: 对象的生存期

 

2.6.1、Boolean 类型

 

2.6.2、Number 类型

 

2.6.3、String 类型: String 对象的方法也可以在所有基本的字符串中访问到。

2.6.3.1、字符方法: charAt()  charCodeAt()

 

2.6.3.2、字符串操作方法:concat()  、slice() 、 substr()  和  substring()

 

2.6.3.3、字符串位置方法:  indexOf()  和 lastIndexOf()

 

2.6.3.4、 trim() 方法

 

2.6.3.5、字符串大小写转换方法:  toLowerCase()  、toLocaleLowerCase() 、toUpperCase()  和   toLocaleUpperCase()

 

2.6.3.6、字符串的模式匹配方法: match()  、search() 、replace()  和 split()

注: replace()  方法的第二个参数也可以是一个函数: 该函数有三个参数(模式的匹配项、 模式匹配项在字符串中的位置  和 原始字符串 )

 

 

2.6.3.7、localCompare() 方法:比较两个字符串,并返回 正数/负数/0

 

2.6.3.8、fromCharCode() 方法: String构造函数本身的一个静态方法,这个方法任务是接收一 或 多个字符编码,任何将它们转换成一个字符串

 

2.7、引用类型  单体内置对象    

如: Object 、 Array 和 String, 还有两个单体内置对象: Global 、 Math

2.7.1、 Global 对象

isNaN() 、 isFinite()  、parseInt() 和  parseFloat() 都是 Global 对象的方法

 


2.7.1.1、URI 编码方法

 


2.7.1.2、eval() 方法: 将传入的参数当作实际的 ECMAScript 语句解析, 然后把执行结果插入到原位置

 


2.7.1.3、Global 对象属性

 


2.7.1.4、window 对象

  • 在 web 浏览器都是讲全局对象作为 window 对象的一部分来实现。
  • 因此,在全局作用域中声明的所有变量和函数,都成为了 window 对象的属性。

 

 

2.7.2、 Math 对象

2.7.2.1、Math 对象属性

 


2.7.2.2、min() max() 方法 , 用于确定一组数值中的最小值 和 最大值

 


2.7.2.3、舍入方法: Math.ceil() 、 Math.floor()  和 Math.round()

 


2.7.2.4、random() 方法: 返回 大于等于 0 小于 1 的一个随机数。(  0 =< x < 1 )

 


2.7.2.5、其他方法

 

 

 

 

2.8、引用类型  小结

对象在JavaScript中被称为引用类型的值,而且有一些内置的引用类型可以用,来创建特定的对象: 

  1. 引用类型  与  传统面向对象程序设计中的类 相似但实现不同;
  2. Object 是一个基础类型,其他所有类型都从 Object 继承了基本的行为;
  3. Array 类型是一 组值的有序列表,同时还提供了操作和转换这些值的功能;
  4. Date 类型提供了有关日期和时间的信息,包括当前日期和时间以及相关的计算功能;
  5. RegExp 类型是ECMASeript支持正则表达式的一个接口,提供了最基本的和一些高级的正则表达式功能。
     

函数实际上是Function类型的实例,因此函数也是对象;   而这一点正 是JavaScript 最有特色的地方。由于函数是对象,所以函数也拥有方法,可以用来增强其行为。

 

因为有了基本包装类型,所以JavaScript中的基本类型值可以被当作对象来访问。三种基本包装类型分别是: Boolean、 Number和String。以下是它们共同的特征:

  1. 每个包装类型都映射到同名的基本类型;
  2. 在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据操作;
  3. 操作基本类型值的语句一经执行完毕,就会立即销毁新创建的包装对象
     

在所有代码执行之前,作用域中就已经存在两个内置对象:  Global Math

在大多数ECMAScript实现中都不能直接访问Global对象;不过,Web浏览器实现了承担该角色的window对象。全局变量和函数都是Global对象的属性。Math对象提供了很多属性和方法,用于辅助完成复杂的数学计算任务。
 

 

 

 

写给自己的随笔,有问题欢迎指出(Θ▽Θ)

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值