博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Javascript 高级程序设计笔记 (cha4 变量作用域和内存)
阅读量:6762 次
发布时间:2019-06-26

本文共 3069 字,大约阅读时间需要 10 分钟。

  hot3.png

#Javascript 高级程序设计笔记 (cha4 变量作用域和内存)

0 问题

一些问题

  1. this 的使用, 有何说道。
  2. 执行环境还可以继续理解。
  3. 栈和堆内存的问题。

1 传递参数

1.1 值传递的问题

javascript的函数是值传递, 这点不要理解错了。 看两个例子。

  • 如果参数是基本数据类型, 那么就是一次复制。 就是说函数里面的那个是外面的复制了一次的变量。所以函数里面的变化不会引起外面全局变量的变化。
  • 那么引用类型呢,是引用的这个值的拷贝, 而不是引用指向对象的拷贝。 相当于把引用的这个值赋给了另外一个引用的变量。具体来说就是在向参数传递引用类型的变量的时候, 会把这个引用对象在内存中的地址赋值给一个局部变量。 - 所以如果在函数中, 这个对象改变了, 也会反映到了外面。

两个例子 1) 当函数内部把对象改变了之后, 全局也变化了。 -

function setName(obj){	obj.name="nick";}var person = new Object();setName(person);alert(person.name); //nick

2) 如果里面改变对象的引用, 比如指向了其他的对象, 再改变那个对象。 原来全局环境的对象是不会改变的。 这也证明了是值传递, 而不是引用传递.

更具体的说。 如果是值传递, 那么一个引用的值赋值给函数内的局部变量, 当指向的obj 的参数那么改变的时候, 外面person1 指向的参数也改了。 而obj 如果new 一个object 那么这个obj 指向了另外一个对象。 这个对象的改变不会引起全局变量的改变。 如果是引用传递, 那么obj 就是person1的这个引用, 而new object, person1的对象也就是new 的这个对象了。 而不是老的obj了。 看下面的结果知道 这里是值传递。

function setName2(obj){	obj.name="nick";	obj = new Object();	obj.name="lily";}var person1 = new Object();setName2(person1);alert(person1.name); //nick

2执行环境和作用域

执行环境

执行环境是一个很重要的概念, 定义了变量或者函数有权访问的其他数据。 每个执行环境都有一个关联的变量对象,(variable object) 这个环境中定义的所有的变量和函数都在这个对象中。 - 我们代码不可以访问, 但是解析器可以。 TODO 什么叫变量对象。

全局执行环境是最外层的一个执行环境。 在浏览器中, 全局执行环境被认为是是window 对象。 所有的全局变量和函数都是座位window 对象的属性和方法来创建的。 当某个执行环境执行完毕, 这个环境就会销毁。

函数- 调用的时候就会创建自己的执行环境, 当执行进入一个函数, 那么函数的环境就被推入一个环境站。 然后函数执行结束, 栈就把他退出来, 把控制权会给之前的执行环境。 TODO 不是很理解。

作用域

scope chain 当代码在执行环境中执行的时候, 会创建一个由变量对象构成的作用域链。 用途是保证对执行环境有权访问的变量和函数的有序访问。 为什么说要有序的。 比如进入一个函数, 那么开始的时候活动对象只是包含一个变量, argument 对象。 作用域链的下一个变量对象是来自外部环境。 再下一个变量对象来自于下一个包含环境。

var color = "blue";function changeColor(){	if(color == "blue"){		color ="red";	}else{		color = "blue";	}}changeColor();alert("color is: " + color);

解读: 进入changecolor里面的时候, 去找color, 本地argument 找不到, 于是到外一个环境去找。

注意: 执行环境, 就是全局环境和函数。 语句块是没有执行环境的, 如下

2.1 关于延长作用域链。

没看太懂, - 懂了 所谓延长就是说 一般就是这个执行环境, 比如函数, 自带的参数会是第一个变量对象。 然后继续外围。 而如果定义变量呢, 其实就是在第一个变量对象里面 (?) 而现在的这两种方式, try/catch 的catch 和with, 相当于在第一个变量的前面加了一个变量。 注意区别。--- 有区别么? 我的理解是, 如果新定义的额变量, 再定义就会override, 毕竟是当前变量对象。 而with引入的这个会在这些之前。 当然你如果在with 里面重新定义了变量, 这些是最优先的, 因为他们已经和with里面都属于第一个变量对象了。

比如with

with(location){	var url = href + " test";}alert("url: " + url);

解读, 这个with把location 这个变量带了进去, 这里不是新定义的, 而是引入了。 这个会在一个function 或者windows 的执行环境的前面加上这个。

2.2 没有块级作用域

这个和java 有显著的区别。

if(true){	var color = "blue";}alert("color: " + color );for (var i = 0; i <5; i++) {	//;}alert("i= " + i);

这两个例子很清楚了。 if block 里面的var 定义color 外面也可以访问。 而for 里面的i, 外面同样可以访问。 好大的坑啊。

2.3 函数中的变量问题

如果函数中的变量没有var, 那么就是说函数外面的执行环境也可以访问, 多大的坑啊。

function test(){	color = "blue";}test();alert(color);	//bluefunction test1(){	var color1 = "blue";}test1();alert(color1); //error

解读: 比如上例。 里面没有var。 执行了之后呢, 外面的执行环境也有了这个变量。 里面如果用了var。 外面就不能再访问了。 这个和java 也是不同的。

3 垃圾收集

首先, javascript 有自动垃圾收集机制的。 所以你不需要操心这个。 那么如何做到的呢, 有两种策略。

  1. 标记清除, 这也是目前使用的。 进入环境就是标记, 然后离开环境就标记离开。
  2. 引用计数。 这个是曾经用的, 简单来说就是把引用的地方记个数字。 会有问题。 什么问题呢? 如果两个对象的属性, 分别互相引用, 那么即使其他的对象对这两个队想已经没有引用了, 这两个地方的引用数字依然不是0. 这就导致了无法释放的严重问题。

尽管不用太操心垃圾回收, 但是由于内存有限和宝贵, 最好能够自己释放, 可以优化应用。 比如在函数中, 对象如果不适用二楼。 可以设置为null。 问题- 这个时候就会释放么, 还是等待一定策略。 我猜测是还是等待但是性能会比你不设置null好, 快。

问题:堆和栈 都是这样自动收集么, 和java 有何不同。 不清楚?

转载于:https://my.oschina.net/sizhe/blog/841464

你可能感兴趣的文章
一维二维码的提取、识别和产生
查看>>
【转】java 自动装箱与拆箱
查看>>
JAVA NIO异步通信框架MINA选型和使用的几个细节(概述入门,UDP, 心跳)
查看>>
【转】android自动化测试之MonkeyRunner使用实例(三)
查看>>
WebService它CXF注释错误(两)
查看>>
html之marquee详解
查看>>
ThinkPad E431/E531 ubuntu 14.04 安装无线网卡驱动
查看>>
ubuntu 中DNAT SNAT配置实验.
查看>>
单位冲击响应与频响以及FIR实现代码(C语言)(转)
查看>>
【R】array 2 string
查看>>
exports与module.exports的区别
查看>>
Handler详细说明系列(六)——View的post()详解
查看>>
ServletWeb缓存解决问题
查看>>
css selector: xpath:
查看>>
Atitit.随时间变色特效 ---包厢管理系统的规划
查看>>
JNDI
查看>>
BZOJ3924 : [Zjoi2015]幻想乡战略游戏
查看>>
电子证书 DER & PEM & CRT & CER
查看>>
基于OpenCL的深度学习工具:AMD MLP及其使用详解
查看>>
[CareerCup] 9.3 Magic Index 魔法序号
查看>>