• js变量、作用域和内存


    一、变量

    1.分类:

    变量可以分为基本类型值和引用类型值,像在之前的随笔中介绍的数值,字符串类型这些就是属于基本类型值。而引用类型值则是指对象。然而,引用类型的值是保存在内存中的对象,js和其他编程语言不同的是,我们不能够直接操作内存中的对象,只能通过当中的引用来操作。所以引用类型的值是按引用访问的。

    2.保存方式:

    基本类型值和引用类型值的保存方式是不一样的,举个例子:

    var person=new object();
    person.name="Nicholas";
    person.age=27;
    alert(person.age);//"Nicholas"
    

      以上例子创建了一个对象,并给该对象添加了一个name属性且赋值Nicholas,这个属性只要对象一直存在就也一样一直存在

    var name="Nicholas";
    name.age=27;
    alert(name.age);//undefined
    

      而这个例子则是给基本变量添加了一个age属性,虽然js不会报错,但是该属性是不存在的

    3.复制变量值

    (1)对于基本类型值,一个变量向另一个变量赋值的时候,会在变量对象上创建一个新值,然后把该值复制到新变量分配的位置上,所以,新变量与原先变量两者是完全独立的。

    (2)对于引用类型值,一个变量向另一个变量复制的时候,则是将指针复制过去,因此,两个变量实际上将引用同一个对象,改变其中一个对象,就会影响另一个对象。

    4.传递参数

    js中参数都是按值来传递的,也就是说,被传递的值如果是基本类型的值,该值将会被复制给一个局部变量。而在传递引用类型的值的时候,会把这个值在内存中的地址传递给一个变量,所以这个局部变量的变化会反映在函数的外部。例如:

    //基本变量
    function addTen(num){ num+=10; return num; } var count =20; var result=addTen(count); alert(count);//20,没有变化 alert(result);//30

    //对象
    function setName(obj){
    obj.name="Nicholas";
    }
    var person=new object();
    setName(person);
    alert(person.name);//"Nicholas"

      *因为在局部作用域中修改的对象会在全局作用域中反映出来,所以很多开发人员认为对象是按引用传递的。为了证明是按值传递,我们来看一个例子:

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

      *因为当函数内部重写obj时,这个变量引用的就是一个局部对象了,所以这个局部对象在函数执行完毕后立即被销毁。因此,在弹出对话框时的内容依旧是Nicholas。故而,参数是按值传递的,如果是按引用来传递的话,obj的name属性的值将会被改变。

    5.检测类型

    前面我们接触过的检测类型是typeof操作符,但是这只适用于基本类型的变量,对于是对象的变量,我们应当使用instanceof。语法如下:

    result=variable instanceof constructor;
    

      例如:

    alert(person instanceof Object);//变量person是 Object吗?
    alert(colors instanceof Array);//变量colors是 Array吗?
    alert(pattern instanceof RegExp);//变量pattern是RegExp吗?
    

      该操作符将返回的是布尔值

    二、执行环境和作用域

    执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为。执行环境分为全局执行环境和局部执行环境。在web浏览器中,全局执行环境被认为是windows对象,因此所有的全局变量和函数都是作为window对象的属性和方法创建的。全局执行环境直到应用程序退出后(例如关闭网页或浏览器)时才会被销毁,保存在其中的变量和函数定义也随之销毁。

    作用域链是用于保证 对执行环境有权访问的所有变量和函数的有序访问,作用域链的前端,始终都是当前执行的代码所在的变量对象。如果这个环境是函数,那么这个函数就是最前的变量对象,往后就是包含在外的一个函数,或是外部变量,一次类推。

    *我们的标识符解析都是沿着作用域链一级级地搜索标识符的过程,所以,全局环境中不可以调用局部环境中的变量。但是局部环境却可以使用全局变量。

     (1)延长作用域链

    有两个方法可以帮助我们延长作用域链:try-catch语句的catch块以及with语句,我们下面重点来了解一下with语句:

    function buildUrl(){
    var qs="?debug=true";
    with(location){
    var url=href+qs;
    }
    return url;
    }
    

      with语句括号内是location对象,当在语句块中引用href的时候,实际上引用的是location.href。with语句使得location的作用域延长到了作用域链的前端。with 语句可以方便地用来引用某个特定对象中已有的属性,去除多次书写对象名的麻烦。但是不能用来给对象添加属性。要给对象创建新的属性,必须明确地引用该对象。

    (2)没有块级作用域链

    在作用域方面,js没有块级作用域链,这和C语言等常见的语言很不一样。js只有全局和局部两种作用域。

    if(true){
    var color="blue";
    }
    alert(color);//blue
    

      在c语言等编程语言当中,因为存在块级作用域,所以color在花括号结束时将被销毁,所以将无法输出color。但是上面例子的代码却能正常输出,这就是因为js把color变量放在了全局环境当中去。所以,color没有被销毁。

    *因为js的这个特点,所以在使用 for语句的时候要格外注意:

    for(var i=0;i<10;i++){
    doSomething(i);
    }
    alert(i);//10
    

      这个时候,输出的i是第十次循环时的i变量

  • 相关阅读:
    zabbix:乱码问题
    zabbix--微信报警(未完成)
    ansible-playbook项目(4)
    ansible-playbook(3)
    备份和校验脚本-邮件通知
    rsync
    keepalived
    双机热备
    nginx负载均衡
    LNMP(5)
  • 原文地址:https://www.cnblogs.com/runhua/p/6486774.html
Copyright © 2020-2023  润新知