JavaScript 变量、作用域与内存

目录

一、原始值与引用值

1、动态属性

2、复制值

3、传递参数

4、确定类型

二、执行上下文与作用域

1、作用域链增强

2、变量声明

三、垃圾回收

1、标记清理

2、引用计数

3、性能

4、内存管理


一、原始值与引用值

原始值就是最简单的数据,引用值则是多个值构成的对象

原始值:Undefined、Null、Boolean、Number、String和Symbol。在把一个值赋值给变量时,js引擎必须确定这个值是引用值还是原始值。保存原始值的变量是按值访问,操作的是存储在变量中的实际值。

引用值:保存在内存中的对象,在操作对象时,实际上操作的是对该对象的引用,而非实际的对象本身。保存引用值的变量是按引用访问的。

1、动态属性

对于引用值而言,可以随时添加、修改和删除其属性和方法

let person = new Object()
person.name = "Tong"
console.log(person.name) //"Tong"

原始值不能有属性,尽管尝试给原始值添加属性不会报错

let name = "Tong"
name.age =  18
console.log(name.log) //undefined

2、复制值

通过把变量的一个原始值赋值到另一个变量时,原始值会被赋值到新变量的位置,两个变量可以独立使用

let num1 = 5
let num2 = num1

在把引用变量从一个变量赋值给另一个变量时,存储在变量中的值也会被复制到新的变量所在的位置。区别在于,这里是一个指针,它指向存储在堆内存中的对象。操作完成后,两个变量实际上指向同一个对象,因此一个对象上的变化会在另一个对象上面反映出来。

let obj1 = new Object()
let obj2 = obj1
obj1.name = "Tong"
console.log(obj2.name)  //"Tong"

3、传递参数

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

在按值传递参数时,值会被复制到一个局部变量(arguments对象中的一个槽位)。在按引用传递参数时,值在内存中的位置会被保存在一个局部变量,这意味着对本地变量的修改会被反映到函数外部。(在ECMAScript中是不可能)

function addTen(num){
    num +=10
    return num
}
let count = 20
let result = addTen(count)
console.log(count)    //20没有变化
console.log(result)   //30

4、确定类型

使用typeof操作符判断一个变量是否为字符串、数值、布尔值或undefined的最好方式(对原始值很有用)

二、执行上下文与作用域

变量或函数的上下文决定了它们可以访问哪些数据,以及它们的行为。

全局上下文是最外层的上下文。在浏览器中,全局上下文就是我们常说window对象。上下文在其所有代码执行完毕后会被销毁,包括定义在它上面所有变量和函数(全局上下文在应用程序退出前才会被销毁)

每个函数调用都会有自己的上下文。上下文中的代码在执行的时候,会创建变量对象的作用域链,这个作用域链决定了各级上下文的代码在访问变量和函数时的顺序。

1、作用域链增强

虽然执行上下文主要有全局上下文和函数上下文两种(eval()调用内部存在第三种上下文),可以其他方式增强作用域链:

  • try/catch语句的catch块
  • with语句

 代码执行到上面任意一种情况时,都会在作用域前端添加一个变量对象。对with语句来说,回乡作用域链前端添加指定的对象;对catch语句而言,则会创建一个新的变量对象,这个变量对象会包含要抛出的错误对象的声明。

2、变量声明

  • 使用var的函数作用域声明

使用var声明变量时,变量会被自动添加到最接近的上下文中。var声明存在变量提升,会被拿到函数或全局作用域的顶部,位于作用域所有代码之前。

  • 使用let的块级作用域声明 

块级作用域由最近的一对花括号{}界定。let与var的另一个不同之处是let同一作用域不能声明两次。重复声明的var会被忽略,而let会抛出SyntaxError

let的声明适合在循环中声明迭代,使用var声明的迭代变量会泄漏到循环外部

for(var i=0;i<10;i++){}
console.log(i)  //10

for(var i=0;i<10;i++){}
console.log(i)  //ReferenceError:i没有定义

 严格来讲,let在JavaScript中运行时也会被提升,但由于暂时性死区的缘故,实际上不能再声明之前使用let变量。

  • 使用const的常量声明

使用const声明的变量必须同时初始化某个值。一经声明,在生命周期的任何时候都不能在重新赋予新值。 

三、垃圾回收

Javascript是使用垃圾回收的语言,执行环境负责在代码执行时来管理内存。实现内存分配和闲置资源回收。基本思路:确定哪个变量不会再使用,然后释放它占用的内存,这个过程是周期性的。

1、标记清理

最常用的垃圾回收策略。当变量进入上下文,比如函数内部声明一个变量时,这个变量会被加上存在于上下文中的标记。当变量离开上下文时也会被加上离开上下文的标记。

垃圾回收程序运行时,会标记内存中存储的所有变量。然后,它会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉。在此之后再被加上标记的变量就是待删除的,原因是任何上下文中的变量都访问不到它们了。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回内存。

2、引用计数

思路:对每个值记录它被引用的次数。当引用次数为0时,释放该值的内存。

3、性能

垃圾回收程序会周期性的运行,如果内存中分配了很多变量,则可能造成性能损失,因此垃圾回收制度的时间调度很重要,尤其在移动设备上,垃圾回收有可能会明显拖慢渲染的速度和帧速率。

4、内存管理

优化内存占用的最佳手段就是保证在执行代码时只保存必要的数据。如果数据不再必要,则设置为null,从而释放其引用(解除引用)

  • 通过const和let声明提升性能

const和let都是使用块作用域,所以相比var,可能会更早地让垃圾回收程序介入,尽早回收。

  • 隐藏类和删除操作
  • 内存泄漏 

意外的全局变量是最常见的也是最容易修复的内存泄漏问题;

定时器也会悄悄地导致内存泄漏

let name = "Tong"
setInterval(()=>{
        console,log(name)
    },100)

 通过闭包引用了外部变量,只要定时器一直运行,回调函数中引用的name就会一直占用内存。垃圾回收程序就不会清理外部变量。

使用闭包是很容易不知不觉中造成内存泄漏

let Outer - function(){
     let name="Tong"
     return function(){
        return name
}  }

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在jQuery中,变量作用域遵循JavaScript作用域规则。 在jQuery中,可以使用`var`关键字声明变量。声明的变量作用域可以是全局作用域或局部作用域。 1. 全局作用域:在任何函数外部声明的变量都具有全局作用域,可以在整个脚本中访问。这意味着在任何地方都可以使用这些变量,包括不同的函数和事件处理程序。 ```javascript var globalVariable = 'I am a global variable'; function foo() { console.log(globalVariable); } foo(); // 输出:I am a global variable ``` 2. 局部作用域:在函数内部声明的变量具有局部作用域,只能在声明它们的函数内部访问。这意味着这些变量只在其所在的函数范围内可见。 ```javascript function bar() { var localVariable = 'I am a local variable'; console.log(localVariable); } bar(); // 输出:I am a local variable console.log(localVariable); // 报错:localVariable is not defined ``` 需要注意的是,在JavaScript中,没有块级作用域。因此,在使用`if`语句、循环等代码块时,声明的变量仍然属于函数作用域。 ```javascript function baz() { if (true) { var blockVariable = 'I am a block variable'; } console.log(blockVariable); } baz(); // 输出:I am a block variable ``` 总结起来,jQuery中的变量作用域遵循JavaScript作用域规则。在函数内部声明的变量具有局部作用域,可以在整个函数内部访问。在函数外部声明的变量具有全局作用域,可以在整个脚本中访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值