【javascript基础】三、变量和做用域

前言

这篇和你们说一下javascript中的变量和做用域,因为是将基础嘛,主要给你们捋一下知识,不想翻开书复习的道友能够看一下,打算刚开始学习javascript的同窗能够扫一眼。javascript

PS:jQuery源码交流群( 239147101)等你来,群里高手云集,让我受益不浅,尽可能少灌水。java

变量

javascript中有两种变量,分别是基本类型和引用类型,基本类型是Null,Undefined,String,Boolean,Number这五种,前面简单的介绍了。引用类型是指Object,Array,Date,RegExp,Function这些。建立这两种变量是相似的,都是建立一个变量而后给它赋值。不一样的缘由主要是在内存中位置和操做不一样。面试

基本类型

基本类型比较简单,基本类型的值保存在栈中。看例子闭包

var v = 1;

基本类型变量在内存中的表示,没有涉及堆函数

看看复制变量以后在内存中的表示,执行的代码以下学习

var v = 1;
var n = v;

解释一下,若是一个变量把基本类型的值复制给另外一个变量时,会建立一个新的相同的值,把这个新的值赋值给新的变量,这样,内存中就有两个同样的值了,分别是新的变量和就的变量指向的值,虽然值是同样的。spa

引用类型

应用类型的变量建立和基本类型的建立是同样的,主要看在内存中的存储方式,代码指针

var obj = new Object();

能够看到,变量obj存储的是一个地址(我的的理解),其实obj的值是一个指针,指向了堆中的对象,能够找到堆中的new出来的对象。再看看复制一个变量时的状况code

var obj = new Object();
var o = obj;

解释一下,这和基本类型的复制是不一样的,咱们能够看出,当一个变量向另外一个变量复制引用类型的值时,也会将存储在变量对象中的值复制一个给新的变量。复制的这个值实际上就是一个指针,指向堆中的一个对象,因为指针是相同的,因此知指向的对象就是同一个对象,此时不管你该哪个变量,都会影响另外一个变量,由于指向的对象是用一个嘛,例如对象

var obj = new Object();
var o = obj;
o.name = "hainan";
console.log(obj.name);//"hainan"

而基本类型则不会,看例子

var v = 1;
var n = v;
v = 100;
console.log(n);//1
console.log(v);//100

这个比较简单,不懂的话看上面的那个内存的图就懂了。

区别

上面说了复制的那个区别,还有一个就是基本类型不能添加属性和方法,而引用类型则能够添加,看例子吧,很简单

//基本类型
var peo = "hainan";
peo .age = 25;
console.log(peo.age);//undefined,可是不报错
//引用类型
var people = new Object();
people.age = 25;
console.log(people.age);//25

函数传参

javascript中函数参数都是按值传递的,也就是把函数外部的值复制给函数内部的参数,和复制变量同样,不管传递的是什么类型,都和复制变量同样。首先看一下传递基本类型的例子

function test(n){
  return n = n+100;  
}
var num = 10;
var result = test(num);
console.log(num);//10 没有发生变化
console.log(result);//110

简单解释一下,调用函数时,传递一个基本类型的参数num给函数,此时,复制值给内部的参数n,这样num和n变量都有了相同的值,可是,这两个之间没有任何的关系,只是值相同而已,想一想前面的图就清楚了,内部的变量也就是参数n改变了以后,num的值并无发生改变。

接下来看看传递引用类型的例子

function test(obj){
  obj.name = "hainan";  
}
var people = new Object();
test(people);
console.log(people.name);//"hainan"

解释一下,其实这个也和复制引用类型变量是同样的,传递一个引用类型给函数参数时,把外部的值复制给内部的函数参数,因为是引用类型这个值是一个指针,因此外部的引用类型变量和内部的参数此时会指向同一个对象,回想上面复制的图,当内部的参数指向的对象改变时,外部的变量指向的对象必定会改变,是同一个对象嘛。

因此,如今你只需知道,传递参数和复制变量是同一回事,不会的时候回想内存中的存储方式就明白了,管它是按值仍是按引用传递呢,只是一个说法罢了,呵呵,可是面试的时候可能会问,记住javascript是值传递就好了。

做用域

执行环境

每一个函数都有本身的执行环境(execution context),执行环境定义了变量和函数有权访问的数据,太官方了,就是每个函数都有本身能够访问的范围,在本身的范围内的数据才能够获得。每个执行环境中都有一个变量对象,保存着该环境中定义的变量和函数。全局执行环境是最外面的一个执行环境,就是window对象,全部的全局变量和函数就是它的属性。每个执行环境执行完以后,这个环境就会被销毁,里面的变量对象也就没有了,固然变量对象中的变量和函数也就销毁了。

做用域

javascript的做用域是指变量和函数能够访问的范围,分为局部做用域和全局做用域,这个和C语言是相似的,可是不一样点是javascript的做用域没有块级做用域,不像C语言的{}能够表示一个块级的做用域,javascript只有函数做用域,在函数内部声明的变量只能在函数体和子函数能够访问,这个函数的外部不能访问。看例子

//没有块级做用域
if(true){
  var n = 1;  
}
console.log(n);//1

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

上面的例子要是在C语言或者java中n和i会在{}语言执行完以后销毁,在javascript中能够看到,它们并无销毁,说明并无块级做用域。

function test(a,b){
  var sum = a + b;  
  return sum;
}
test(1,2);//3
console.log(sum);//sum is not defined

能够看出sum是在函数的外部访问不到的,由于sum函数是在函数的局部做用域中定义的,在函数执行结束时,内部的变量就会销毁,因此外部的做用域访问不到它,这就是函数的做用域。

做用域链

做用域链(scope chain)是保证在执行环境中有序的访问变量和函数,咱们能够这样想,每一个函数都有一个本身的执行环境,这个执行环境的嵌套就像套娃是同样的,大的套小的,内部的执行环境的变量有权访问外部的执行环境的数据,而外部的不能够反问内部的,因此当内外的执行环境中都有一个相同的变量或函数时,你是先访问哪个呢?因此就有了做用域链这个概念。这个做用域链的每个节点是一个变量对象,函数中有一个活动变量对象的概念,刚开始时只有函数的arguments对象,以后会把当前的变量对象中的变量和函数复制到活动对象中。做用域链的第一个变量对象是活动对象,以后就是下一个包含环境,以后是包含环境的包含环境......直到全局执行环境的变量对象。 看例子可能你们会明白

function test(a,b){
  var  sum = a + b;
  return sum; 
}
var s = test(1,2);

分析上面的这段代码,在未调用test()函数以前,看看做用域链状况

在未执行函数的时候,能够看到函数的做用域链只用一个全局的变量对象,里面有window和test函数等,在执行var s = test(1,2);语句的时候,做用域链会发生变化,会增长一个函数的活动对象到做用域链的前面,这个活动对象的初始值只有函数的arguments对象,以后会把函数的内部变量等复制到这个活动对象中,请看下面的图

这就是函数的做用域链,之后要访问某个变量的时候,会沿着这个做用域链进行查找,即沿着活动对象->外部函数的活动对象->外部函数的外部函数的活动对象->......->终点的全局执行环境,在这期间在某个活动对象中内部有这个值就会返回这个值,这个过程就会中止,不在进入另外一个执行环境中,看个例子

//全局变量
var color = "red";
function getColor(){
    //内部变量
    var color = "blue";
    return color;
}
console.log(getColor());//blue

看到这里你们会明白了。

PS:其实javascript的闭包和做用域链有很大的联系,这里咱不讨论,闭包会单独讨论。

小结

这就是javascript的做用域了,主要你们仍是好好看看变量内存那块,分析几个就会了。注意一下javascript没有块级做用域这一说法,这点你们要当心了。最近几每天天在群里看你们的聊天记录,论文也不想写了,哎,坐等回家吃猪肉了,但愿老师别鄙视我。

相关文章
相关标签/搜索