资讯专栏INFORMATION COLUMN

变量和作用域

Codeing_ls / 953人阅读

摘要:当代码在一个环境中执行时,会创建变量对象的一个作用域链,作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的下一个变量对象则来自下一个包含环境。

前言

JavaScript中变量是松散类型,这样它只在特定的时间内用于保存一个特定的值。由于不存在定义某个变量必须要保存何种数据类型的规则,变量的值和其数据类型可以在脚本的生命周期内改变。

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

JavaScript中变量可能包含两种不同类型的值: 基本类型和引用类型。 基本类型值指的是简单的数据段,而引用类型指的是那些可能多个值构成的对象。

JavaScript中有5种基本类型的值:Number, String, Null,Undefined, Boolean。这5种基本类型是按值访问的,因为可以操作保存在变量中的实际的值

引用类型的值是保存在内存中的对象。 与其他语言不同, JavaScript不允许直接访问内存中的位置, 也就是说不能直接操作对象的内存空间。 在操作对象时, 实际上是操作对象的引用而不是实际的对象。因此,引用类型的值是按引用访问的。

注意: 当复制保存着对象的某个变量时, 操作的是对象的引用。 但在为对象添加属性的时候,操作的实际的对象

1.1 动态的属性

定义基本类型值和引用类型值得方式是类似的:创建一个变量并为该变量赋值。对于引用类型的值来说,我们可以为其添加属性和方法,也可以改变和删除其属性和方法。但是基本类型的值却不行。

var person = new Object()
person.name = "Nicholas"
alert(person.name) //"Nicholas"

如上,我们创建一个对象,并保存在person。然后为该对象添加一个name属性,最后通过person.name可以访问这个新属性,如果对象不被销毁或者这个属性不被删除,则这个属性将一直存在。

如果我们给基本类型的值添加属性,虽然不会导致错误,但是这样是不合理的:

var name = "Nicholas"
name.age = 27
alert(name.age) //undefined
1.2 复制变量值

除了保存的方式不同,从一个变量向另一个变量复制基本类型值和引用类型值时也存在不同。如果一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。

var num1 = 5
var num2 = num1

当从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。不同的是,这个值得副本实际上是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响另一个变量:

var o1 = new Object()
var o2 = o2
o1.name = "Nicholas"
alert(o2.name) //Nicholas

1.3 传递参数

ECMAscript中所有的函数参数都是按值传递的,也就是说,把函数外部的值复制给函数内部参数,就和把值从一个变量复制到另一个变量一样。基本类型的传递如同基本类型变量的复制一样,而引用类型值得传递如何引用类型变量的复制一样。

在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(即命名参数,就是arguments对象中的一个元素)。在向参数传递引用类型的值时,会把这个值在内存中的地址复制一个给局部变量,因此这个局部变量的变化会发生在外部。但是这样总会感觉参数还是通过按引用传递的。下面这个例子可以证明是按值传递:

var person = new Object()
function setName(obj) {
    obj.name = "Nicholas"
    obj = new Object()
    obj.name = "Greg"
}
setName(person)

如果person是按引用传递的,那么person会被改成一个新对象,但是当你继续访问person.name的时候返回的是"Nicholas"。这说明即使在函数内部修改了参数的值,但是原始的引用仍然保持未变。实际上当函数内部重写obj时,这个变量引用的就是一个局部对象了,而这个局部对象会在函数执行完毕后销毁。

2. 执行环境和作用域

执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有与之关联的变量对象。执行环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。

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

当代码在一个环境中执行时,会创建变量对象的一个作用域链,作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行代码所在的环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。活动对象在最开始时只包含一个变量,即argument对象。作用域链的下一个变量对象则来自下一个包含环境。这样一直延续到全局环境。

标识符解析是沿着作用域链一级一级的搜索标识符的过程。

2.1 延长作用域链

有些语句可以在作用域链的前端临时增加一个变量对象, 该变量对象会在代码执行后被移除。在两种情况下会发生这种现象,具体来说就是当执行流进入下列任何一个语句时,作用域链会得到加长。

try-catch的catch块

with语句

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93046.html

相关文章

  • 深入理解JavaScript作用作用

    前言 JavaScript中有一个被称为作用域(Scope)的特性。虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域和作用域链,希望大家有所收获! 想阅读更多优质文章请猛戳GitHub博客 作用域(Scope) 1.什么是作用域 作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,作用域决定了代码区块中变量和其他资源的可见...

    baiy 评论0 收藏0
  • 深入理解JavaScript作用作用

    前言 JavaScript中有一个被称为作用域(Scope)的特性。虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域和作用域链,希望大家有所收获! 想阅读更多优质文章请猛戳GitHub博客 作用域(Scope) 1.什么是作用域 作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,作用域决定了代码区块中变量和其他资源的可见...

    ytwman 评论0 收藏0
  • JavaScript-作用、块级作用、上下文、执行上下文、作用

    摘要:一旦函数执行完成,其就会从作用域链顶部移除,并且执行权会返回到函数。攀爬作用域链当不同执行上下文之间存在变量命名冲突,可以通过攀爬作用域链解决从顶部到底部。 一、作用域 在 JavaScript 中, 作用域(scope,或译有效范围)就是变量和函数的可访问范围,即作用域控制着变量和函数的可见性和生命周期 二、全局/局部作用域 2.1 全局作用域(Global Scope) (1)不...

    Coding01 评论0 收藏0
  • 大话javascript 1期:作用作用

    摘要:全局作用域局部作用域局部作用域全局作用域局部作用域块语句没有块级作用域块级声明包括和,以及和循环,和函数不同,它们不会创建新的作用域。局部作用域只在该函数调用执行期间存在。 一、什么是作用域? 作用域是你的代码在运行时,各个变量、函数和对象的可访问性。(可产生作用的区域) 二、JavaScript中的作用域 在 JavaScript 中有两种作用域 全局作用域 局部作用域 当变量定...

    NicolasHe 评论0 收藏0
  • 讲清楚之javascript作用

    摘要:并且作用域链也确定了在当前上下文中查找标识符后返回的值。为了具象化分析问题,我们可以假设作用域链是一个数组,数组成员有一系列变量对象组成。注意,所有作用域链的最末端都为全局变量对象。所以作用域作用域链都是在当前运行环境内代码执行前就确定了。 什么是作用域(Scope)? 作用域产生于程序源代码中定义变量的区域,在程序编码阶段就确定了。javascript 中分为全局作用域(Global...

    whidy 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<