简略草稿简记(重点简记)
基本类型和引用类型
其实这部分我们就是在讨论Object类型(引用类型)和其他类型(Null、String、Number、Undefined、Boolean)的一些操作的区别。
ECMAScript标准包含两种不同的数据类型:基本类型值 和 引用类型值。
引用类型值 是保存在内存中的对象,JavaScript不允许直接访问内存中的位置,即不能直接操作对象中的内存空间。(像C语言那样直接通过访问内存来改变变量?)
所以,对基本类型的操作,就是对保存在内存中的实际值的操作,但是对引用类型值的操作就是对对象引用的操作。
var person = new Object();//引用类型
person.name = "Nicholas";
alert(person.name);
var name = "Nicholas";//基本类型
name.age = 27;
alert(person.name);
我们来对比一下以上的代码段:
第一个代码段首先定义了一个新的对象(或者说我们常说的C语言中的类),可以理解为这是一个空对象,我们并没有对其进行任何初始化。之后我们可以动态的向其中添加属性,比如以上的name属性,并且可以直接为其进行初始化。这种操作是有效的
第二个代码段我们首先定义了一个变量(基本类型String),之后为其添加属性age,但这种操作是无效的。
拷贝操作
对于基本类型操作就是和C/C++相同,考赋值拷贝就是开辟一个新的内存空间,两个值分别是不同的对象,占用内存不同位置,对一个对象的改变不会影响另一个。
但对于Object类型则不然,实际上是对引用的拷贝,入下,拷贝后,对一个对象的操作会影响另一个,因为实际上二者占用的是同一内存空间。实际上是对指针的副本拷贝。
var obj1 = new Object();
var obj2 = obj1;
obj1.name = 'ctr_temp';
alert(obj2.name);
实际上打印出的是'ctr_temp'
可见,对其中一个对象的改变影响了另外一个Object对象。
参数传递
这部分是关于函数参数传递的讨论,其实发现很多部分还是要借鉴关于C/C++的前景知识,这部分理解起来很快。
C++中介绍了关于传引用以及传值的两种传参区别,这里JavaScript只有一种方式进行参数传递:值传递。
对于基本类型,由于无法通过访问内存空间地址来访问变量,我们同样无法通过传指针(其实也是传值的一种)来间接的访问改变传入的实参。
function num_add(num)
{
num+=10;
return num;
}
var count = 100;
var count_add = num_add(count);
alert(count);//打印出来是100,原值没有改变
alert(count_add);//打印出来是110
对于Object类型(引用类型),我们需要着重理解一下:对于引用类型我们其实也是传值。
function set_Name(obj){obj.name = 'ctr_temp';}
var person = new Object();
set_Name(person);
alert(person.name);//打印出来是ctr_temp,被改变了!!!
以上看来,似乎对于引用类型的传参是传引用了!实则不然,我们来回忆一下传值传参的基础:实际上传值传参是先对实参进行一个拷贝,用拷贝后的临时值对形参进行初始化。
再加上刚刚第一部分的知识:对于Object类型的拷贝实际上是对指针进行副本拷贝,拷贝和被拷贝赋值的对象指向的是同一个内存地址,那么即使是传值,我们也可以通过这种方式对传入的引用类型实参进行改变。方便立即不如看看以下的实例。
function set_name(obj)
{
obj.name = "ctr_temp";
obj = new Object();
obj.name = "CTR_Temp";
}
var person = new Object();
set_name(person);
alert(person.name);
可想而知,如果按以上的方式进行传值操作,我们得到的应该是"ctr_temp"
因为之后创建的新对象(开辟新空间)其实是一个局部变量,函数结束后即销毁,
而我们想要访问打印的还是原始对象。
(当然,如果是传引用操作的得到的就应该是"CTR_Temp"了)
检测类型
主要介绍instanceof操作符,用来返回变量类型是否是引用,如果是引用类型就返回true。
instanceof
执行环境以及作用域
其实就是类似于C/C++关于局部变量以及全局变量的一个讨论!局部作用域以及全局作用域,屏蔽以及访问的优先级关系!
var color = 'yellow';
//这里,在最外层作用域,你可以访问color
function search_color ()
{
var ano_color = 'orange';
//在这里,相对内层一些的作用域,你可以访问 ano_color以及color
function swap_color()
{
var color_temp = 'red';
//在这里,所有外层内层定义的变量都是可以访问的
}
//可以访问 color,ano_color
any_func();
}
//只可以访问color
search_color();
在这里,内部属于子执行环境,其外部都是其父执行环境,子执行环境可以访问一切其上级的父执行环境中定义的变量,反之则不允许。
关于延长作用域链
这里涉及with语句以及 try-catch语句,暂时不提
关于块级作用域
之前关于JavaScript的blog中提到过,JavaScript中不涉及块级作用域这个概念,在语句块内部定义的语句在外部是可以访问到的(当然不是函数中定义的那种),如下for语句和if语句的示例:
以下的两个语句块,内部定义的变量在外部仍可以被访问到
if(true){var color = 'blue';}
alert(color);
for(var index = 0; index<100; ++index)
{/*...*/}
alert(index);
function add(num1, num2)
{
var sum = 0;
sum = num1+num2;
return sum;
}//对于此函数,sum对于外部是不可以访问的
function add_ano(num1, num2)
{
sum = num1+num2;
return sum;
}//这种定义形式的sum(没有var关键字),外部可以访问sum
//sum被默认为是一个全局变量
注意:我们不建议以上的第二种写法!!!
查询标识符
实际上是一种对变量的查找索引方式,如下例子可以很好的说明:
var color = 'blue';
function find_color(){return color};
alert(find_color());//返回blue
程序执行时,首先从当前的作用域(子作用域,这里就是函数内层作用域)进行搜寻,无法找到color对象时开始向上层作用域进行搜寻(这里就是全局作用域),找到后返回‘blue’,搜索过程结束。
即,搜寻过程逐级向上,内层能够搜索到就停止继续向上搜寻。这样来看,与C/C++相同,内部定义使用的变量对象,将会隐藏外部的同名定义!
内存管理——垃圾收集
对于C/C++之类的语言来说,开发人员的一个基本任务就是手工跟踪内存的使用情况(造成一些问题的根源)。
这部涉及内存管理的问题,当我学完C++相关部分后,再来对此部分进行补充(目前先进行浅显的简要理解)。
待解决问题
1、对于我想在函数内部(内层作用域)访问外部(外层作用域)的对象的情况,应该怎样做呢?