变量声明

javascript 使用var + 变量名 声明变量,因为javascript是弱类型语言,

所有我们可以随意更改已有变量的类型。

  1. var b=1;
  2. b='2',

另外不同于c#中的var隐式类型推断必须在声明变量式指定变量值,

编译器会根据值类型推导出变量类型。

而在javascript中我们可以只声明变量而暂不赋值,对于未赋值的变量,其类型和值都是undefined

  1. var a;
  2. console.log(a);//output:undefined
  3. typeof a //output :undefined;

作用域与变量提升

javascript中不存在块级作用域,只存在所谓通常指一对花括号中的语句,

常见的 有if--else try --catch for循环等

例如在c#中

  1. for(var i=0;i<10;i++)
  2. {
  3. }
  4. Console.WriteLine(i)//error: The name 'a' does not exist in the current context

而在javascript因为没有块级作用域,只有全局作用域和函数作用域,在块中声明的变量等同在当前变量作用域中(全局或者函数作用域)

直接声明

  1. for(var i=0;i<10;i++){
  2. }
  3. console.log(i);//output: 10;

当我们使用到一个变量时,会现在当前作用域内查找,那如果找不到怎么办?理论上函数应该能访问一个更高一层上下文的变量对象。

实际上它正是这样,这种机制是通过函数内部的[[scope]]属性来实现的。

[[scope]]是所有父变量对象的层级链,处于当前函数上下文之上,在函数创建时存于其中

简单来说,[[scope]]保存了当前上下文所有的变量对象,指定了变量的搜索范围。

需要强调的是 函数的作用域链在创建时就作为一个属性存在,是静态不变的,不受调用上下文影响。

  1. var a=0,c=3;
  2. function test(){
  3. var a=10;
  4. var b=1;
  5. /*创建时[[scope]]属性保存调用上下文的变量对象,包含test函数作用域变量{a,b},以及全局作用域{a,c}*/
  6. function fun1(){
  7. console.log(a);
  8. console.log(c);
  9. }
  10. fun1();//调用时,先查找自身作用域范围内是否有a,c 变量,如果没有,则在[[scope]]中根据上下文逐层查找。 output:10,3;
  11. fun2();//调用时,同样先查找活动变量,然后在[[scope]]中的查找,即在全局变量中搜索。 output:0,ReferenceError: b is not defined;
  12. }
  13. //创建时,其上下文为全局对象,故其[[scope]]属性包含全局变量{a,c}
  14. function fun2(){
  15. console.log(a);
  16. console.log(b);
  17. }

javascript编程范式通常建议我们在将可能用到的变量都声明到代码的顶部,这样做不仅更直观还能避免一些因为变量提升引发的异常

所谓变量提升是指:JavaScript 会提升变量声明。这意味着 var 表达式和 function 声明都将会被提升到当前作用域的顶部。

  1. var myvar = 'my value';
  2. (function() {
  3. console.log(myvar); //output: undefined
  4. var myvar = 'local value';
  5. })();

由于没有块级作用域,for循环中的变量声明会被提升到当前作用域的顶部

  1. var a=10;
  2. for(var i =0;i<10;i++){
  3. var x =i;
  4. }

该代码等同于

  1. var a,i, x;
  2. a=10;
  3. for(i =0;i<10;i++){
  4. x =i;
  5. }

另外虽然var 和function 都会提升到变量的顶部,但如果存在同名函数声明,函数声明会覆盖掉变量声明

  1. console.log(a);// output: function a(){};
  2. var a =1;
  3. console.log(a);//output: 1;
  4. a=2;
  5. function a(){};
  6. console.log(a); //output:2;

如果未用var 声明一个变量,而直接赋值,会使得其成为全局对象的一个属性。

  1. var c,b;a;//错误的分号导致a没有被正常声明
  2. console.log(a);//output:ReferenceError: a is not defined; 没有变量提升
  3. a=2;
  4. window.a //output: 2 浏览器中全局对象对实现为window

变量类型与参数传递

  • 变量类型与赋值

    javascript中的类型分为值类型和引用类型,值类型的值保存在栈中,它们的值直接存储在变量访问的位置。

    引用类型存储在堆中,变量保存的是对象的引用,指向存储对象的内存处,一般我们可以简单理解为

    变量存储对象的指针,但该引用不等同与指针,不能进行指针的相关操作(p++).

    javascript中值类型即原始类型 Undefined、Null、Boolean、Number 和 String,虽然在一些语言如c#中string被实现为引用类型,

    但在javascript中string为值类型。其余的对象均为引用类型, 我们可以 typeof value ===object 判断,但是需要排除null,这通常被认为javascript实现上的一个错误

    关于引用类型变量重要的一点是,但如果我们将一个新对象赋值给已有变量,改变量保存的引用地址会发生改变,但如果我们更新了一个对象的属性,该对象的内存地址并不会改变,

    改变的只有内存对象的值。下面的代码将说明这个问题。
  1. var a ={m:1}; //假设{m:1}的内存地址为0x001 则a保存的地址变量为 0x001
  2. var b=a; // b同时指向0x001
  3. a.x = a ={n:2}; //变量的赋值是同时进行的,也就是 a.x={n:2}和a={n=2}是没有先后顺序的.
  4. // 假设{n:2} 地址为0x002 则 变量a 的地址被重新指向到 0x002, 同时原地址 0x001对象增加一个x属性指向0x002;
  5. //现有0x001地址对象为{m:1,x:{n:2}};
  6. console.log(a.x); //因为a的指向0x002 即{n:2},所以输出 undefined;
  7. console.log(b.x); //因为b指向 0x001 即{m:1,x:{n:2}},所以输出 {n:2};
  • 参数传递

    首先明确一点,如果变量是值类型,即javascript中的原始类型,是按值拷贝传递的,如果是引用类型,传递的是地址引用,虽然也有叫法说javascript对引用对象是按引用传递,然而这并不准确

    真正的引用传递是
  1. class PassingRefByRef
  2. {
  3. static void Change(ref int[] pArray)
  4. {
  5. pArray[0] = 888;
  6. pArray = new int[5] {-3, -1, -2, -3, -4};
  7. System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
  8. }
  9. static void Main()
  10. {
  11. int[] arr = {1, 4, 5};
  12. System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]);
  13. Change(ref arr);
  14. System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]);
  15. }
  16. }
  17. /* Output:
  18. Inside Main, before calling the method, the first element is: 1
  19. Inside the method, the first element is: -3
  20. Inside Main, after calling the method, the first element is: -3
  21. */

所以javascript的参数传递是按值传递,不过对于引用对象,传递的值是参数的引用地址,同样的,当我们为参数重新赋值时,实际上改变了参数指向的地址。

  1. var a = {};
  2. var b={};
  3. (function test(a,b){
  4. a.x=1; // 对a指向地址的变量修改,方法外a 同时被修改
  5. b={x:1}; // 变量被指向新地址,方法外 b 不变
  6. })(a,b);

es6下的变量

  • Let,const

    ES6新增了let命令,用来声明变量。作用同var一致,但具有块级作用域。

    const用来声明常量,const的作用域与let命令相同:只在声明所在的块级作用域内有效。

    let和const目前只能在严格模式下使用,并且不具备变量提升
  1. 'use strict'
  2. console.log(a); //ReferenceError: a is not defined; 没有变量提升
  3. let a =1;
  4. window.a;//不同与var 声明的全局变量不会成为全局对象的属性
  5. if(true){
  6. const PI= 3.14;
  7. PI= 3.1415926; //默默的失败
  8. console.log(PI);//output: 3.14
  9. }
  10. console.log(PI);//output:ReferenceError: PI is not defined,仅在块中有效
  • 解构赋值

    ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构

    以前我们可以这样
  1. var a=1,b=2,c=3;

现在我们可以这样:

  1. var [a,b,c]=[1,2,3]; //数组顺序很重要
  2. a;//1
  3. b;//2
  4. c;//3
  5. var { bar, foo } = { foo: "aaa", bar: "bbb" }; //属性名要匹配
  6. foo // "aaa"
  7. bar // "bbb"

引用参考 > http://segmentfault.com/q/1010000002637728

javascript变量浅析的更多相关文章

  1. javascript变量的作用域

    javascript变量的作用域 基本类型和引用类型 基本类型值指的是简单的数据段,而引用类型值指的是那个可能由多个值组成的对象  讲一个值赋值给变量时,javascript解析器首先要确定是基本类型 ...

  2. JavaScript 变量声明提前

    <JavaScript权威指南>中指出:JavaScript变量在声明之前已经可用,JavaScript的这个特性被非正式的称为声明提前(hoisting),即JavaScript函数中声 ...

  3. JavaScript 变量

    一,JavaScript 变量(存储信息的容器) 与代数一样,JavaScript 变量可用于存放值(比如 x=2)和表达式(比如 z=x+y). 变量可以使用短名称(比如 x 和 y),也可以使用描 ...

  4. javascript变量声明 及作用域

    javascript变量声明提升(hoisting) http://openwares.net/js/javascript_declaration_hoisting.html 可能要FQ一下 java ...

  5. JavaScript 变量作用域

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

  6. 【转】javascript变量声明 及作用域

    javascript变量声明提升(hoisting) javascript的变量声明具有hoisting机制,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面. 先看 ...

  7. JavaScript变量和数据类型

    变量 变量就是一个元素,类似于数学中的概念,用来指定表示一个对象.在JavaScript中,用来指定变量的关键字为var.当声明新变量时,可以使用关键词 "new" 来声明其类型 ...

  8. 回归基础: JavaScript 变量提升

    from me: javascript的变量声明具有hoisting机制,它是JavaScript一个基础的知识点,也是一个比较容易犯错的点,平时在开发中,大大小小的项目都会遇到. 它是JavaScr ...

  9. JavaScript - 变量,作用域,内存

    JavaScript 变量可以用来保存两种类型的值:基本类型值和应用类型值.基本类型的值源自以下5种基本数据类型:Undefined.Null.Bollean.Number和String. 所有变量都 ...

随机推荐

  1. RPDU

    RPDU(Remote Power Distribution Unit) 又称网络电源控制系统.远程电源管理系统.智能PDU.智能电源分配系统,是由傲视恒安科技(北京)有限公司自主研发生产并在全国范围 ...

  2. Python的程序入口 __name__属性

    python中每个模块都有一个 '__name__' 属性,当其值为 '__main__' 时,表名该模块自身在运行,否则是被引入的. 当一个模块被当做一个整体调用的时候,模块名.__name__ 的 ...

  3. 事务 TRANSACTION

    事务是数据库中一个但单独的执行单元(Unit),他通常由高级数据库操作语言(如SQL)或编程语言(如C++.Java)编写的用户程序的执行所引起.当在数据库中更改数据成功时,在事务中更改的数据便会提交 ...

  4. Linux产生序列数字

    {起始数字..结束数字}    //  注意 起始数字和结束数字都包括在内 中间没有空格

  5. datagrid 扩展 页脚 合计功能

    效果图:合计信息展示在页脚中(showFooter:true) code: <!DOCTYPE html> <html> <head> <meta chars ...

  6. 博客写作的Checklist

    Checklist 1.不要发明术语. 2.不要使用指代不清的代词.如:我,他. 3.不要使用错误的承前省. 4.不要使用口语. 5.给出结论之前,先交代背景. 6.站立会议报告中应有燃尽图. 7.燃 ...

  7. java中HashMap的基本方法使用

    遍历,添加词,等等 package test; import java.util.HashMap; import java.util.Iterator; import java.util.ArrayL ...

  8. ios蓝牙自定义快捷键

    http://www.paopaoche.net/app/12072.html Beekeyboard  

  9. Android Studio 老提示adb问题

    Android Studio 老提示adb问题,restart后任然无解,最后发现某手机助手软件占用端口... 解决步骤: C:\Users\xxx>netstat -ano | findstr ...

  10. 59.加载Viewcontroller的几种方法(添加导航,解决xib里面空间不显示问题)

    // 一.根据StoryboardID(需要在Storyboard设置),通过ViewController所在的Storyboard来加载: UIStoryboard *storyboard = [U ...