zoukankan      html  css  js  c++  java
  • 2015第35周五JavaScript变量

    java语言里有一句很经典的话:java的世界里,一切皆是对象

    Javascript虽然跟java没有半点毛关系,但是很多会使用javascript的朋友同样认为:javascript的世界里,一切也皆是对象

      其实javascript语言和java语言一样变量是分为两种类型:基本数据类型和引用类型。

      基本类型是指:Undefined、Null、Boolean、Number和String;而引用类型是指多个指构成的对象,所以javascript的对象指的是引用类型。在java里能说一切是对象,是因为java语言里对所有基本类型都做了对象封装,而这点在javascript语言里也是一样的,所以提在javascript世界里一切皆为对象也不为过。

      Javascript里的基本变量是存放在栈区的(栈区指内存里的栈内存),它的存储结构如下图所示:


       javascript里引用变量的存储就比基本类型存储要复杂多,引用类型的存储需要内存的栈区和堆区(堆区是指内存里的堆内存)共同完成,如下图所示:

      在javascript里变量的存储包含三个部分:

        部分一:栈区的变量标示符;

        部分二:栈区变量的值;

        部分三:堆区存储的对象。

    JS中变量赋值和函数传参都是传递栈区的值。JS中的变量未定义不能访问,但可以不用var定义而直接出现在赋值语句中,此时相当于在全局通过var定义该变量,实际上是window的一个属性。

     其实javascript里的变量和其他语言有很大的不同,javascript的变量是一个松散的类型,松散类型变量的特点是变量定义时候不需要指定变量的类型,变量在运行时候可以随便改变数据的类型,但是这种特性并不代表javascript变量没有类型,当变量类型被确定后javascript的变量也是有类型的。但是在现实中,很多程序员把javascript松散类型理解为了javascript变量是可以随意定义即你可以不用var定义,也可以使用var定义,其实在javascript语言里变量定义没有使用var,变量必须有赋值操作,只有赋值操作的变量是赋予给window,这其实是javascript语言设计者提升javascript安全性的一个做法。

      此外javascript语言的松散类型的特点以及运行时候随时更改变量类型的特点,很多程序员会认为javascript变量的定义是在运行期进行的,更有甚者有些人认为javascript代码只有运行期,其实这种理解是错误的,javascript代码在运行前还有一个过程就是:预加载,预加载的目的是要事先构造运行环境例如全局环境,函数运行环境,还要构造作用域链,而环境和作用域的构造的核心内容就是指定好变量属于哪个范畴,因此在javascript语言里变量的定义是在预加载完成而非在运行时期。

    var ooo = null;
    
        console.log(ooo);// 运行结果:null
    
        console.log(ooo == undefined);// 运行结果:true
    
        console.log(ooo == null);// 运行结果:true
    
        console.log(ooo === undefined);// 运行结果:false
    
        console.log(ooo === null);// 运行结果:true
    复制代码

      运行之,结果很震惊啊,null居然可以和undefined相等,但是使用更加精确的三等号“===”,发现二者还是有点不同,其实javascript里undefined类型源自于null即null是undefined的父类,本质上null和undefined除了名字这个马甲不同,其他都是一样的,不过要让一个变量是null时候必须使用等号“=”进行赋值了。

      当变量为undefined和null时候我们如果滥用它javascript语言可能就会报错,后续代码会无法正常运行,所以javascript开发规范里要求变量定义时候最好马上赋值,赋值好处就是我们后面不管怎么使用该变量,程序都很难因为变量未定义而报错从而终止程序的运行,例如上文里就算变量是string基本类型,在变量定义属性程序还是不会报错,这是提升程序健壮性的一个重要手段,由引子的例子我们还知道,变量定义最好放在变量所述作用域的最前端,这么做也是保证代码健壮性的一个重要手段。

    函数传递参数的本质就是外部的变量复制到函数参数的变量里,我们看看下面的代码:

    复制代码
        function testFtn(sNm,pObj){
    
            console.log(sNm);// 运行结果:new Name
    
            console.log(pObj.oName);// 运行结果:new obj
    
            sNm = "change name";
    
            pObj.oName = "change obj";
    
        }
    
        var sNm = "new Name";
    
        var pObj = {oName:"new obj"};
    
        testFtn(sNm,pObj);
    
        console.log(sNm);// 运行结果:new Name
    
        console.log(pObj.oName);// 运行结果:change obj
     var ftn1 = function(){
    
            console.log("test:ftn1");
    
        };
    
        var ftn2 = function(){
    
            console.log("test:ftn2");
    
        };
    
        function ftn(f){
    
           f();
    
           f = ftn2;
    
        }
    
        ftn(ftn1);// 运行结果:test:ftn1
    
        console.log("====================华丽的分割线======================");
    
        ftn1();// 运行结果:test:ftn1
    复制代码

      这个代码是很早之前有位朋友考我的,我当时答对了,但是我是蒙的,问我的朋友答错了,其实当时我们两个都没搞懂其中缘由,我朋友是这么分析的他认为f是函数的参数,属于函数的局部作用域,因此更改f的值,是没法改变ftn1的值,因为到了外部作用域f就失效了,但是这种解释很难说明我上文里给出的函数传参的实例,其实这个问题答案就是函数传参的原理,只不过这里加入了个混淆因素函数,在javascript函数也是对象,局部作用域里f = ftn2操作是将f在栈区的地址改为了ftn2的地址,对外部的ftn1和ftn2没有任何改变。

      记住:javascript里变量复制和函数传参都是在传递栈区的值

      栈区的值除了变量复制起作用,它在if语句里也会起到作用,当栈区的值为undefined、null、“”(空字符串)、0、false时候,if的条件判断则是为false,我们可以通过!运算符计算,因此当我们的代码如下:

    复制代码
        var obj = {};
    
        if (!!obj){
    
            console.log("true");
    
        }else{
    
            console.log("false");
    
        }
    复制代码

      结果则是true,因为var obj = {}相当于var obj = new Object(),虽然对象里没什么内容,但是在堆区里,对象的内存已经分配了,而变量栈区的值已经是内存地址了,所以if语句判断就是true了。

    谈谈javascript语法里一些难点问题(一)

  • 相关阅读:
    【版本控制工具】 Git进阶1
    【版本控制工具】 Git基础
    问题:com.alibaba.dubbo.rpc.RpcException: Failed to invoke ......
    互联网安全架构之常见的Web攻击手段及解决办法
    【Spring Boot】七、整合actuator实现监控管理
    问题:tomcat启动后,可以访问主页面,但是无法访问dubbo-admin
    【Spring Boot】六、整合dubbo(注解的方式)
    这篇文章,彻底搞懂八大开源框架源码
    Spring Cloud Greenwich.SR4 发布了,跟不上了……
    手把手教你画架构图,看一次就会了!
  • 原文地址:https://www.cnblogs.com/doit8791/p/4768149.html
Copyright © 2011-2022 走看看