变量,作用域知识
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