1、变量及作用域
(1)ECMAScript的两种数据类型:基本类型、引用类型值
a、基本类型:栈内存中简单的数据段(完全保存在内存中的一个位置)
b、引用类型:堆内存中的对象(保存实际上只是一个指针,该指针指向内存中的另一个位置,该位置保存对象)
当把一个值赋值给变量时,解析器必须确定是基本类型,还是引用类型
a、基本类型(5种):undefined、null、boolean、string、number
特点:有固定大小的空间,值保存在栈空间
注意:某些语言中,字符串string以对象的形式来表示,被认为引用类型,ECMAScript放弃该传统
b、引用类型:Object{}类型
特点:内存大小不固定,值保存在堆内存空间中
操作:当查询引用类型的变量时,先从栈中读取内存地址,再通过地址找到堆中的值,即按引用访问。
不同点:基本类型按值访问,引用类型按引用访问
(2)动态属性
a、定义类型值方式为:创建一个变量为该变量赋值,
var box=new Object(); //{}
box.name=‘zhao’; //新建一个属性
alert(box.name);
b、基本类型
var box='zhao' ; //基本类型值,是字符串;
box.age=28;
alert(box.age); //undefined;
由于上述代码不引用类型,所以无法输出
(3)复制变量的值
基本类型:值本身
引用类型:复制为地址
a、基本类型
var box='Lee'; //保存在box'Lee'
var box2=box; //栈内润再生成一个‘box2 'Lee'’
box2='kk'; //基本类型保持独立,box不会进行复制
alert(box); //Lee
alert(box2); //kk
b、引用类型
var box=new Object(); //创建一个引用类型;
box.name='Lee';
var box2=box;
alert(box.name); //‘Lee’
alert(box2.name); //Lee
上述代码中,由于是按照地址传递,所以box与box2是相同的,即当box.name变化时,box2.name也会变化。
(4)传递参数
a、基本类型(按值传递)
function box(num){
num+=10;
return num;
}
var num=50;
alert(box(num)); //60
alert(num); //50
//(若按引用传递,那么函数量的num会成为类似于全局变量,也就是说,最后会打印60)
注意:Javascript中不会按照引用传递,所以不可能打印出60,但在php文件中可以按引用传递,即为全局变量
demo1.php(按引用传递)
';
echo num; //60
?>
b、引用传递(传参引用参数)
function box(obj){ //按值传递参数,传递一个引用类型的参数,而不是按值传参,
obj.name='Lee';
var obj=new Object(); //所以,js没有按引用传递参数功能,不能把传递引用参数当成引用传参
obj.name='kkk';
}
var obj=new Object();
box(obj);
alert(obj.name);
结果:Lee
解析:若按引用传参,即结果为“kkk”,但是新建的object对象,表现的不能被外界看到。
易混点——按引用传递和传递引用类型
这两个是不同的概念:
(1)按引用传递:函数中变量为全局变量,在外部也可以访问
(比如php中,必须在参数前加&号表示按引用传递)
(2)传递引用类型:函数中变量为局部变量,在外部不可以访问
总结:ECMAScript中没有按引用传递,只能是局部变量,在PHP中可以实现。
(5)检测类型
A——基本类型
必须采用typeof运算符进行检测,但对于引用类型typeof就不可以,若不是检测是否为对象,而是检测是何种类型的对象,采用instanceof运算符
function box(obj){ //按值传递参数,传递一个引用类型的参数,而不是按值传参,
obj.name='Lee';
var obj=new Object(); //所以,js没有按引用传递参数功能,不能把传递引用参数当成引用传参
obj.name='kkk';
}
var obj=new Object();
box(obj);
alert(obj.name);
总结:数组array,空对象null,正则表达式regexp都表示的是“对象”;
B——引用类型
案例5-1:用instanceof运算符检测引用类型
var box1=[1,2,3];
alert(instanceof Array); //是否为数组,返回true;
var box2={};
alert(instanceof Object) ; //是否为对象,返回true;
var box3=/g/;
alert(instanceof RegExp); //是否为正则表达式,返回false;
区别:typeof运算符、instanceof运算符
(1)typeof——检测基本类型,一般返回基本类型(如object、number、string、null、boolean、undefined)
(2)instanceof——检测引用类型,检测某一个变量是否为某一个数据类型,通常返回的是true或false
(注意:当用instanceof检测基本类型时,会返回false,见案例4-2)
案例5-2:
var box=String();
alert(box instanceof String); //检测box是否为对象,返回false(由于string为基本类型)
若想返回true,即需要用基本类型方式来创建对象,见案例4-3
案例5-3:
var box=new Object('Lee');
alert(box instanceof String); //返回true(由于有new关键字)
注意——
对基本类型而言,(1)若有new关键字创建对象并检测时,用instanceof运算符
(2)若无new关键字直接创建对象时,用typeof运算符
(6)执行环境及作用域
a、对于全局变量,位于最外围,属于window属性
b、对于全局函数,位于最外围,属于window的方法
案例6-1:
var box='blue';
function setBox(){
alert(window.box); //全局变量即window的属性
}
window.setBox(); //全局函数即window的方法;
注意:当执行完所有代码后,该环境被销毁,保存在其中的变量也将随之被销毁。
c、作用域“全局作用域window”、“局部作用域”
c-1:若局部子函数中有var,即为局部变量;若无var,即可以取代之前的全局变量
var box='Lee';
function setBox(){
//var box='red';
//局部变量,范围在setBox中,出去就被销毁,结果为“Lee”
box='red';
//box为全局变量,结果为“red”
}
setBox();
alert(box);
(2)当传参数时,也为局部变量
var box='Lee';
function setBox(box){ //通过传参,也是局部变量,作用与在setBox中;
alert(box);
}
setBox('red');
alert(box);
结果:仍为“Lee”,由于该参数box在setBox()函数中,“red”参数进去执行完毕即被销毁,并没有传递到window下。
(3)当函数中包含着函数,即被包含的函数也是局部变量
var box='Lee';
function setBox(){
function setColor(){ //setColor()执行作用域在setBox()中;
//var b='kkk'; //变量b作用域位于setColor()中
//alert(b);
return 123;
}
}
alert(window.setBox()); //123
(6)没有块级作用域
块级作用域,即诸如if语句等花括号封闭的代码块,
所以,支持条件判断莱斯你故意变量。
案例1:if、for语句没有封闭作用域的功能,即可被外围访问,window下的全局变量。
if(true){
var box='Lee';
}
alert(window.box);
案例6-2:var关键字在函数中使用
function box(){
//var num=10; //有var,在函数体内声明变量,表示局部变量。
num=10; //无var,在函数体内表示全局变量
}
box();
alert(num);
(7)变量查询
向上查询搜索的功能
var box='blue';
function getColor(){
var box='red';
return box;
}
alert(getColor());
结果:返回red,由于在getColor()函数中已经存在box对象,就不必向外部window进行上一级搜索。
2、内存问题
(1)Javascript有自动垃圾收集功能,也就是说,执行环境会负责管理代码执行过程中使用的内存。
(2)Javascript最常用的垃圾收集方式:标记清除。
(垃圾收集器会在运行的时候给存储在内部变量加上标记,会去掉环境中正在使用变量的标记,而没有被去掉的标记视为准备删除的变量,最后当垃圾收集器完成内存清理工作,销毁那些带标记的值并回收他们所占用的内存空间)。
(3)优化内存的性能方法:一旦数据不再使用,将其设置为null来释放引用,即“解除引用”,
适用于大多数全局变量和全局对象
案例2-1:null解除引用的案例
var box={};
box.name='Lee';
alert(box.name); //Lee
box=null; //销毁引用,等待清理;
alert(box); //null
但是,若为window的时候,不可以解除引用
案例2-2:
var box='Lee';
alert(window.box); //Lee
window=null;
alert(window); //Lee
解析:由于window不可能被设置为null。