变量,作用域知识

1、基本类型和引用类型的值

ECMAscript的变量和其他语言变量有所不同,其为松散型变量,每个变量只是一个占位符而已。变量可能包含两种类型的值

一种为基本类型的值,在内存中占据固定大小,保存在栈内存中,简单的数据段,string,number,Boolean,null,undefined,

一种为引用类型的值,指可能为多个值构成的对象,object,保存在堆内存中;引用类型的值保存在内存中的对象,js不允许直接操控内存中的对象。实际操控对象的引用来操控对象,其变量是个指向该对象的指针。

1.1动态的属性

当操作变量时候,对于引用类型的值,可以添加属性,方法,可以改变,删除属性和方法;但是对于基本类型的值,就不可以添加属性(虽然不会产生错误)

        //基本类型的值
        var name="double";
        name.age=27;
        name.sex="man";
        console.log(name.age)     //undefined


        //引用类型的值
        var person=new Object();
        person.name="double";
        person.age=20;
        person.sex="man"
        console.log(person.name)   //double

1.2复制变量的值

对于基本类型来说,复制变量值就是clone了,两个变量完全独立,没有任何关系

对于引用类型来说,复制变量值实际复制的只是个指针,指向存储在堆中的一个对象,两个变量实际将引用同一个对象改变任意一个,都将改变

        //对于基本类型,复制之后完全独立,没有关系
        var one=12;
        var two=one;
        one=13;
        console.log(one)    //13
        console.log(two)    //12
    
        //对于引用类型,变量名只是指针,引用的是同一个对象    
        var obj1=new Object();
        var obj2=obj1;
        obj1.name="double";
        obj1.sex="man";
        obj2.sex="woman";
        console.log(obj2.name)   //double
        console.log(obj1.sex)    //woman

1.3传递参数

js中所有函数参数都是按值传递的。

把函数外部的数复制给参数,基本类型的传递如同基本变量的复制一样,而引用类型的传递如同引用变量的复制一样。但是参数是按值传递的。

在传递基本类型值时,被传递的值复制给局部变量(也就是命名参数),仅仅是值得修改。

在传递引用类型值时,将这个值再内存中的地址复制给局部变量,因此这个局部变量的变化会反映在函数的外部。

        function add(num){
             num+=10;
             return num;
        }
        var count=20;
        var result=add(count)
        console.log(count)     //20
        console.log(result)    //30

        function setName(obj){
            obj.name="double";   //函数的内部,obj和person引用的是同一对象,即使参数是按值传递的
            obj=new Object();    //即使函数内部被修改,但是原有的引用未改变,重写obj时,变量的引用只是局部变量,函数执行完毕立刻被销毁
            obj.name="single";
        }
        var person=new Object();
        setName(person);
        console.log(person.name);   //double

1.4检测类型

检测基本数据类型时,一般用操作符typeof,但是当类型为null和对象时,检测的都是object;检测引用类型,想知道某个类型的对象用instanceof操作符。

        var person=new Object();
        var colors=[];
        var pattern=/d/;
        console.log(person instanceof Object)  //都是true
        console.log(colors instanceof Array)
        console.log(pattern instanceof RegExp)
当instanceof检测引用类型和Object构造函数时,始终会返回true;而检测基本数据类型则为false

2、执行环境和作用域

执行环境(execution context)定义了变量或者函数有权访问的其他数据,定义了它们各自的行为。每个环境中都有一个与之相关的变量对象,环境中定义的所有变量和函数都保存在这个对象中,全局执行环境是最外围的执行环境,即window对象。某个执行环境中所有代码执行完毕后,该环境被销毁。

执行环境有全局环境和函数环境两种

当代码在一个环境中执行,会创建变量对象的一个作用域链,以保证对执行环境有权访问的所有变量和函数的有序访问.

        var color="blue";
        function change(){
             var anotherColor="red";
             function changeAgain(){
                  var tempColor=anotherColor;
                  anotherColor=color;
                  color=tempColor; 
                 console.log(tempColor)       //red
                 console.log(anotherColor)    //blue
                 console.log(color)           //red
              }
                 // console.log(tempColor)    访问不到
                 console.log(anotherColor)    //red
                 console.log(color)           //blue
                 changeAgain()
          }
                 // console.log(tempColor)    访问不到
                 // console.log(anotherColor) 访问不到
                 console.log(color)           //blue
                 change()

内部环境可以通过作用域链访问所有的外部环境,而外部环境不能访问内部环境的任何变量和函数

2.1延长作用域链

有些语句可以在作用域链的前端临时加个变量对象,代码执行后就移除,

try-catch语句中的catch块;with语句。

2.2没有块级作用域

js中是没有块级作用域的,所以if内的变量就是window对象下的;for循环的变量同是

       if(true){
               var color="red";
       }
       console.log(color) //red

       for(var i=0;i<10;i++){
              console.log(i)  //0-9
       } 
       console.log(i)      //10

声明变量

涉及到var操作符,有var声明则是局部变量,没有则是全局变量,在函数的执行环境内,外部是访问不到的 。

查询标识符

在某个环境中引用一个标识符,必须通过搜索来确认该标识符代表着什么,先从自身环境搜索,然后沿着作用域链向上溯回查询,一旦找到就OK。

       var color="red";
       function getColor(){
               return color
       }
       console.log(getColor())  //red

基础不牢,地动山摇

posted @ 2018-01-29 00:04  决起而飞  阅读(303)  评论(0编辑  收藏  举报