// JS变量是松散型的(不强制类型)本质,决定了它只是在特定时间用于保存特定值的一个名字而已;

// 由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变;

一 变量及作用域

1.基本类型和引用类型

 // JS变量包含两种不同的数据类型的值:基本类型值和引用类型值;

 // 1.基本类型值:保存在栈内存中的简单数据段;即这种值完全保存在内存中的一个位置;
// 基本类型值包含:Undefined|Null|Boolean|Number|String;
// 这些类型在内存中占有固定大小的空间;它们的值保存在栈空间,我们按值来访问; // 2.引用类型值:保存在堆内存中的对象(可能由多个值构成),即变量中保存的实际上只是一个指针,这个指针指向内存中的另一个位置,该位置保存对象;
// 引用类型的值的大小不固定,因此不能保存在栈内存,必须保存在堆内存中;但可以将引用类型的值的内存地址保存在栈内存中;
// 当查询引用类型的变量时,先从栈内存中读取内存地址,然后通过地址找到堆内存中的值;=>按引用访问;

2.动态属性

 // 定义基本类型值和引用类型值的方式相似:创建一个变量并为该变量赋值;
// 但当这个值保存到变量中以后,对不同类型值可以执行的操作则不一样;
var box = new Object(); // 创建引用类型;
box.name = 'lee'; // 新增一个属性;
console.log(box.name); // =>lee; var box = 'lee'; // 创建基本类型
box.age = 15; // 给基本类型添加属性;
console.log(box.age); // =>undefined;

3.复制变量值

 // 在变量复制方面,基本类型和引用类型也有所不同;
// 基本类型赋值的是值本身;
var box = 'lee'; // 在栈内存中生成一个box'lee';
var box2 = box; // 在栈内存中再生成一个box2'lee';
// box和box2完全独立;两个变量分别操作时互不影响; // 引用类型赋值的是地址;
var box = new Object(); // 创建一个引用类型;box在栈内存中;而Object在堆内存中;
box.name = 'lee'; // 新增一个属性;
var box2 = box; // 把引用地址赋值给box2;box2在栈内存中;
// box2=box,因为它们指向的是同一个对象;
// 如果这个对象中的name属性被修改了,box.name和box2.name输出的值都会被修改掉;

4.传递参数

 // JS中所有函数的参数都是按值传递的,即参数不会按引用传递;
function box(num){ // 按值传递,传递的参数是基本类型;
num +=10; // 这里的num是局部变量,全局无效;
return num;
}
var num = 50;
var result = box(num);
console.log(result); // 60;
console.log(num); // 50; function box(num){
return num;
}
console.log(num); // num is not defined; function box(obj){
obj.name = 'lee';
var obj = new Object(); // 函数内部又创建了一个对象,它是局部变量;但在函数结束时被销毁了;
obj.name = 'Mr'; // 并没有替换掉原来的obj;
}
var p = new Object();
box(p); // 变量p被传递到box()函数中之后就被复制给了obj;在函数内部,obj和p访问的是同一个对象;
console.log(p.name); // =>lee; // JS函数的参数都将是局部变量;也就是说,没有按引用传递;

5.检测类型

 // 要检测一个变量的类型,通过typeof运算符类判断;
// 多用来检测基本类型;
var box = 'lee';
console.log(typeof box); // =>string; // 要检测变量是什么类型的对象,通过instanceof运算符来查看;
var box = [1,2,3];
console.log(box instanceof Array); // =>true;
var box2 = {};
console.log(box2 instanceof Object);
var box3 = /g/;
console.lgo(box3 instanceof RegExp);
var box4 = new String('lee');
console.log(box4 instanceof String); // =>true;是否是字符串对象; var box5 = 'string';
console.log(box5 instanceof String); // =>false;
// 当使用instanceof检查基本类型的值时,它会返回false;

6.执行环境及作用域

 // 执行环境:定义了变量或函数有权访问的其他数据,决定了它们各自的行为;
// 在Web浏览器中,全局执行环境=window对象;
// 因此所有的全局变量和函数都是作为window对象的属性和方法创建的;
var box = 'blue'; // 声明一个全局变量;
function setBox(){
console.log(box); // 全局变量可以在函数里访问;
}
setBox(); // 执行函数;
// 全局的变量=window对象的属性;
// 全局的函数=window对象的方法; // PS:当执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁;
// 如果是在全局环境下,需要程序执行完毕,或者网页被关闭才会销毁; // PS:每个执行环境都有一个与之关联的变量对象,就好比全局的window可以调用全局变量和全局方法一样;
// 局部的环境也有一个类似window的变量对象,环境中定义的所有变量和函数都保存在这个对象中;
// (我们无法访问这个变量对象,但解析器会处理数据时后台使用它);
var box = 'blue';
function setBox(){
var box = 'red'; // 这里是局部变量,在当前函数体内的值是'red';出了函数体就不被认知;
console.log(box);
}
setBox();
console.log(box); // 通过传参可以替换函数体内的局部变量,但作用域仅限在函数体内这个局部环境;
var box = 'blue';
function setBox(box){ // 通过传参,将局部变量替换成了全局变量;
alert(box); // 此时box的值是外部调用时传入的参数;=>red;
}
setBox('red');
alert(box); // 如果函数体内还包含着函数,只有这个内函数才可以访问外一层的函数的变量;
// 内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数;
var box = 'blue';
function setBox(){
function setColor(){
var b = 'orange';
alert(box);
alert(b);
}
setColor(); // setColor()的执行环境在setBox()内;
}
setBox();
// PS:每个函数被调用时都会创建自己的执行环境;当执行到这个函数时,函数的环境就会被推到环境栈中去执行,而执行后又在环境栈中弹出(退出),把控制权交给上一级的执行环境; // PS:当代码在一个环境中执行时,就会形成一种叫做作用域链的东西;它的用途是保证对执行环境中有访问权限的变量和函数进行有序访问;作用域链的前端,就是执行环境的变量对象;

7.延长作用域链

 // 有些语句可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除;
// with语句和try-catch语句;这两个语句都会在作用域链的前端添加一个变量对象;
// with语句:会将指定的对象添加到作用域链中;
// catch语句:会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明;
function buildUrl(){
var qs = '?debug=true';
with(location){ // with语句接收的是location对象,因此变量对象中就包含了location对象的所有属性和方法;
var url = href+qs; // 而这个变量对象添加到了作用域链的前端;
};
return url;
}

8.没有块级作用域

 // 块级作用域:表示诸如if语句等有花括号封闭的代码块,所以,支持条件判断来定义变量;
if(true){ // if语句代码块没有局部作用域;
var box = 'lee'; // 变量声明将变量添加到当前的执行环境(在这里是全局环境);
}
alert(box); for(var i=0; i<10; i++){ // 创建的变量i即使在for循环执行结束后,也依旧会存在与循环外部的执行环境中;
var box = 'lee';
}
alert(i);
alert(box); function box(num1,num2){
var sum = num1+num2; // 此时sum是局部变量;如果去掉var,sum就是全局变量了;
return sum;
}
alert(box(10,10));
alert(sum); // sum is not defined;访问不到sum;
// PS:不建议不使用var就初始化变量,因为这种方法会导致各种意外发生; // 一般确定变量都是通过搜索来确定该标识符实际代表什么;搜索方式:向上逐级查询;
var box = 'blue';
function getBox(){
return box; // 此时box是全局变量;如果是var box='red',那就变成局部变量了;
}
alert(getBox());
// 调用getBox()时会引用变量box;
// 首先,搜索getBox()的变量对象,查找名为box的标识符;
// 然后,搜索继续下一个变量对象(全局环境的变量对象),找到了box标识符;
// PS:变量查询中,访问局部变量要比全局变量更快因为不需要向上搜索作用域链

二 内存问题

 // JS具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存;它会自行管理内存分配及无用内存的回收;

 // JS最常用的垃圾收集方式就是标记清除;垃圾收集器会在运行的时候给存储在内存中的变量加上标记;
// 然后,它会去掉环境中正在使用的变量的标记,而没有被去掉标记的变量将被视为准备删除的变量;
// 最后,垃圾收集器完成内存清理工作,销毁那些标记的值并回收他们所占用的内存空间; // 垃圾收集器是周期性运行的,这样会导致整个程序的性能问题;
// 比如IE7以前的版本,他的垃圾收集器是根据内存分配量运行的,比如256个变量就开始运行垃圾收集器,这样就不得不频繁地运行,从而降低了性能; // 一般来说,确保占用最少的内存可以让页面获得更好的性能;
// 最佳方案:一旦数据不再使用,将其值设置为null来释放引用,这个做法叫做解除引用;
var o = {
name:'lee';
};
o = null; // 解除对象引用,等待垃圾收集器回收;

三 小结

 1.变量
// JS变量可以保存两种类型的值:基本类型值和引用类型值;它们具有以下特点:
// 1.基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中;
// 2.从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本;
// 3.引用类型的值是对象,保存在堆内存中;
// 4.包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针;
// 5.从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向用一个对象;
// 6.确定一个值是哪种基本类型可以使用typeof操作符;而确定一个值是哪种引用类型可以使用instanceof操作符; 2.作用域
// 所有变量都存在于一个执行环境(作用域)中,这个执行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量;
// 1.执行环境有全局执行环境和函数执行环境之分;
// 2.每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;
// 3.函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其父环境,乃至全局环境;
// 4.变量的执行环境有助于确定应该合适释放内存; 3.内存
// JS自动垃圾收集机制
// 1.离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除;
// 2.为了确保有效地回收内存,应该及时解除不再使用的全局对象/全局对象属性以及循环引用变量的引用;

JavaScript--变量、作用域及内存(12)的更多相关文章

  1. 第一百零六节,JavaScript变量作用域及内存

    JavaScript变量作用域及内存 学习要点: 1.变量及作用域 2.内存问题 JavaScript的变量与其他语言的变量有很大区别.JavaScript变量是松散型的(不强制类型)本质,决定了它只 ...

  2. JavaScript变量作用域和内存问题(二)

    执行环境是js中特别重要的概念,是指变量或者函数可以访问其他数据,定义自己的行为.每个执行环境都有一个与之相对应的变量对象,执行环境中定义的所有变量和函数都保存在这个变量中,我们看不到这个变量,但是后 ...

  3. 【转】javascript变量作用域、匿名函数及闭包

    下面这段话为摘抄,看到网上大多数人使用的是变量在使用的时候声明而不是在顶端声明,也可能考虑到js查找变量影响性能的问题,哪里用就在哪里声明,也很好. 在Javascript中,我们在写函数的时候往往需 ...

  4. JavaScript 变量作用域

    一. 变量声明 变量用var关键字来声明,如下所示: 变量在未声明的情况下被初始化,会被添加到全局环境. JavaScript执行代码时,会创建一个上下文执行环境,全局环境是最外围的环境.每个函数在被 ...

  5. 深入理解Javascript变量作用域

    在学习JavaScript的变量作用域之前,我们应当明确几点: a.JavaScript的变量作用域是基于其特有的作用域链的. b.JavaScript没有块级作用域. c.函数中声明的变量在整个函数 ...

  6. JavaScript变量作用域(Variable Scope)和闭包(closure)的基础知识

    在这篇文章中,我会试图讲解JavaScript变量的作用域和声明提升,以及许多隐隐藏的陷阱.为了确保我们不会碰到不可预见的问题,我们必须真正理解这些概念. 基本定义 作用范围是个“木桶”,里面装着变量 ...

  7. JavaScript变量作用域

    全部变量拥有全局作用域,局部变量拥有局部作用域(这里注意函数的参数也是局部变量) 1.在函数体内,局部变量的优先级高于同名的全局变量. 我的理解就是当你同时定义了同名的局部变量和全局变量时,函数体内返 ...

  8. JavaScript 变量类型 保存内存中的位置 和 引用

    1. JavaScript变量 基本类型值在内存中占据固定大小的空间 因此被保存在栈内存中. 从一个变量向另一个变量复制基本来下的值 会创建这个值得一个副本. 引用类型的值是对象 保存在堆内存中. 包 ...

  9. JavaScript 变量作用域 详解

    变量作用域要点 - 在JavaScript中没有块级作用域,只有函数作用域 - 在函数体内,局部变量的优先级高于同名的全局变量 - 在全局作用域编写代码时可以不写var语句,但声明局部变量时必须使用v ...

  10. 基础系列(1)之干掉JavaScript变量作用域

     今天去某顺公司面试,发现一些基础知识都不记得了,于是乎决定把js基础系列的全部梳理一遍,今天就整理下js变量作用域的相关基础知识点,配合最常遇到的笔试题阐述. 题一: var g = "a ...

随机推荐

  1. 【原创】省市二级联动纯javascript

    // 北京 上海 天津 重庆 河北 山西 内蒙古 辽宁 吉林 黑龙江 江苏 浙江 安徽 福建 江西 山东 河南 湖北 湖南 广东 广西 海南 四川 贵州 云南 西藏 陕西 甘肃 宁夏 青海 新疆 香港 ...

  2. httpclient发起https请求以及获取https返回内容

    工作中的需要,使用Apache httpclient发起获取通过https返回的内容,试了很多网上的解决办法都不行,查阅了Apache httpclient的官方文档,最后终于找出解决方法,分享给需要 ...

  3. Codefoces 429 D. Tricky Function

    裸的近期点对.... D. Tricky Function time limit per test 2 seconds memory limit per test 256 megabytes inpu ...

  4. Swift学习笔记八

    函数 Swift的函数语法非常独特,也提供了很高的灵活性和可读性.它可以充分表达从简单的无参数C风格函数到复杂的拥有局部变量和外部变量的OC风格的方法.参数可以有默认值,方便函数的调用.Swift中的 ...

  5. javascript实现继承的方式

    this this表示当前对象,如果在全局作用范围内使用this,则指代当前页面对象window: 如果在函数中使用this,则this指代什么是根据运行时此函数在什么对象上被调用. 我们还可以使用a ...

  6. 使用NuGet安装EntityFramework4.2

    1.下载NuGet 有两种方式下载NuGet 第一种:在微软的档案库下载,下载地址为:http://visualstudiogallery.msdn.microsoft.com/27077b70-9d ...

  7. 使用iOS手势UIGestureRecognizer

    UIKit中包含了UIGestureRecognizer类,用于检测发生在设备中的手势.UIGestureRecognizer是一个抽象类,定义了所有手势的基本行为,它有下面一些子类用于处理具体的手势 ...

  8. 【转】winform退出代码:Application.Exit和Environment.Exit(0)

    Application.Exit和Environment.Exit(0)有什么退出方面的区别吗? Application.Exit:通知winform消息循环退出.会在所有前台线程退出后,退出应用 强 ...

  9. ZOJ 2588 Burning Bridges(求含重边的无向连通图的割边) - from lanshui_Yang

    Burning Bridges Time Limit: 5 Seconds Memory Limit: 32768 KB Ferry Kingdom is a nice little country ...

  10. 《嵌入式Linux基础教程》补充阅读建议电子数目下载

    第二章 <Linux内核设计与实现(原书第三版)> <深入理解Linux内核(第三版)> <深入理解Linux虚拟内存管理> 其他与Linux相关的电子书下载地址: ...