JavaScript有两种数据类型:基本数据、引用数据。
基本数据类型有:undefined、null、布尔类型、数字类型、字符类型,基本类型值是简单的数字段。访问基本类型的变量是以值访问的。
引用类型是对象,它是object类型的实例,引用类型值是可能多个值的对象。
引用类型值是保存在内存中的,而JavaScript不能直接访问内存的,所以对于引用类型,操作的不是实际的对象,而是对象的引用。访问引用类型的变量是以引用访问的(当为对象添加属性时不是以引用访问的)。
引用类型存放的是指向某个对象的指针
J avaScript中对象可以动态添加属性并赋值的。
先定义一个对象并赋值给变量obj,obj存放指向对象的指针,动态地给obj对象的属性name赋值"changjiuhuang",最后输出对象属性name的值。
基本数据类型不可以添加属性。
如上,定义一个变量num1并赋值,接着定义了一个变量num2形成新的空间,将num1中的值复制并存放在了num2空间中,此时,两个变量中的值是相互独立无影响的,如上将num1中的值复制给了num2中,再改变num1中的值,这时num2中的值依然是1,说明基本数据类型的两个变量是不相互影响和相互独立的。
由关键字new和构造函数Object定义了一个对象obj1,并为obj1动态添加属性name并赋值"javscript",接着将obj1中的值赋值给了obj2,输出obj2为"javascript",这时,我们再重新为obj1的属性name赋值"This is javascript",最后再输出obj2的值为"This is javascript",我们发现,再次改变obj1的属性的值,obj2的属性的值也会相应改变,这是为什么?
所谓参数传递,就是将一个变量 复制并赋值 给另一个变量。这里将person引用复制并赋值给参数obj,所以person与obj均是一个指向同一个对象的引用。
在向参数传递基本类型值时,被传递的参数会复制给一个局部变量(即命名参数,argument对象中的一个元素)。在向参数传递引用类型值时,会把这个值在内存中的地址(指针)复制给一个局部变量,因此这个局部变量的变化会反应在函数的外部,如:
传递基本类型值:
这里的参数num就是一个局部变量,count作为参数被传递给函数,count的值会被复制给num以便在addTen中使用,在函数内部num会加上10,但不会影响函数外部的count变量,num与count是互不影响的。若传递的是引用类型值情况就不一样了。
传递引用类型值:
以上创建一个对象并保存在变量person中,并将person传递到setName()函数中并复制给了obj。obj是一个局部变量,此时person与obj都指向同一个对象(这个对象是一个全局对象),于是,在函数内部为obj添加name属性后,person也有了相应的反应,因为person指向的对象在堆内存中只有一个,而且是全局对象。
为了证明对象参数是按值传递的,如下例子:
与上述例子不同的地方是:在setName()函数内部重新定义了obj对象,并为其添加name属性,在person传递给了setName()后,obj的属性设置为"changjiuhuang",然后又将新对象赋给obj,同时将其name属性值设为"javascript",如果person是按引用传递的,那么person也会修改为指向属性值为"javascript"的新对象,但接下来person.name依然弹出的是"changjiuhuang"。这说明,即使在函数内部修改了参数的值,但原来的引用仍然保持不变(原对象是一个全局对象)。在函数内部重新定义obj对象时,这个变量只是一个局部对象,在函数执行完成后会被销毁的。
基本数据类型有:undefined、null、布尔类型、数字类型、字符类型,基本类型值是简单的数字段。访问基本类型的变量是以值访问的。
引用类型是对象,它是object类型的实例,引用类型值是可能多个值的对象。
引用类型值是保存在内存中的,而JavaScript不能直接访问内存的,所以对于引用类型,操作的不是实际的对象,而是对象的引用。访问引用类型的变量是以引用访问的(当为对象添加属性时不是以引用访问的)。
引用类型存放的是指向某个对象的指针
访问变量有两种方法:按值访问、按引用访问
动态属性
J avaScript中对象可以动态添加属性并赋值的。
var obj = new Object();
obj.name = 'changjiuhuang';
console.log(obj.name) //changjiuhuang
先定义一个对象并赋值给变量obj,obj存放指向对象的指针,动态地给obj对象的属性name赋值"changjiuhuang",最后输出对象属性name的值。
基本数据类型不可以添加属性。
复制变量值
基本数据类型
var num1 = 1;
var num2 = num1;
num1 = 2;
console.log(num1);
console.log(num2);
如上,定义一个变量num1并赋值,接着定义了一个变量num2形成新的空间,将num1中的值复制并存放在了num2空间中,此时,两个变量中的值是相互独立无影响的,如上将num1中的值复制给了num2中,再改变num1中的值,这时num2中的值依然是1,说明基本数据类型的两个变量是不相互影响和相互独立的。
引用数据
var obj1 = new Object()
obj1.name = "javascript";
var obj2 = obj1
console.log(obj2.name); //javascript
obj1.name = "This is javascript"
console.log(obj2.name) //This is javascript
由关键字new和构造函数Object定义了一个对象obj1,并为obj1动态添加属性name并赋值"javscript",接着将obj1中的值赋值给了obj2,输出obj2为"javascript",这时,我们再重新为obj1的属性name赋值"This is javascript",最后再输出obj2的值为"This is javascript",我们发现,再次改变obj1的属性的值,obj2的属性的值也会相应改变,这是为什么?
原来,这是将第一个变量的值复制给了第二个变量,因为引用类型存放的是指向对象的指针,所以两个变量都存放的是指针并指向同一个对象,当改变其中一个变量的值时,也就相当于改变了该变量指向的对象中的值,则另一个变量的值也会相应改变,
我们来看另一个例子:
function sayName (obj) {
obj.name = "tom";
obj = new Object(); //这里变量引用的是局部对象。原始引用的值未改变。
obj.name = "bob";
}
var person = new Object();
sayName(person);
console.log(person.name); //tom
所谓参数传递,就是将一个变量 复制并赋值 给另一个变量。这里将person引用复制并赋值给参数obj,所以person与obj均是一个指向同一个对象的引用。
注意:两个变量所指向的对象是一个全局对象,如果在函数体中单独改变其中一个变量的值,被改变的变量只能算是指向一个局部对象, 另一个变量的值不会改变,一般用于传递参数的例子。
传递参数
不管是基本数据还是对象,参数都是 按值传递的。在向参数传递基本类型值时,被传递的参数会复制给一个局部变量(即命名参数,argument对象中的一个元素)。在向参数传递引用类型值时,会把这个值在内存中的地址(指针)复制给一个局部变量,因此这个局部变量的变化会反应在函数的外部,如:
传递基本类型值:
function addTen(num) {
num += 10;
return num;
}
var count = 20;
var result = addTen(count);
alert(count); //20,没有变化。
alert(result); //30
这里的参数num就是一个局部变量,count作为参数被传递给函数,count的值会被复制给num以便在addTen中使用,在函数内部num会加上10,但不会影响函数外部的count变量,num与count是互不影响的。若传递的是引用类型值情况就不一样了。
传递引用类型值:
function setName(obj) {
obj.name = "changjiuhuang";
}
var person = new Object(); //定义一个对象
setName(person);
alert(person.name); //弹出"changjiuhuang"
以上创建一个对象并保存在变量person中,并将person传递到setName()函数中并复制给了obj。obj是一个局部变量,此时person与obj都指向同一个对象(这个对象是一个全局对象),于是,在函数内部为obj添加name属性后,person也有了相应的反应,因为person指向的对象在堆内存中只有一个,而且是全局对象。
为了证明对象参数是按值传递的,如下例子:
function setName (obj) {
obj.name = "changjiuhuang";
var obj = new Object(); //重新定义一个对象,这是一个局部对象,在函数执行完后会被销毁。
obj.name = "javascript"; //并为该对象添加name属性。
}
var person = new Object();
setName(person);
alert(person.name); //弹出的还是"changjiuhuang"
与上述例子不同的地方是:在setName()函数内部重新定义了obj对象,并为其添加name属性,在person传递给了setName()后,obj的属性设置为"changjiuhuang",然后又将新对象赋给obj,同时将其name属性值设为"javascript",如果person是按引用传递的,那么person也会修改为指向属性值为"javascript"的新对象,但接下来person.name依然弹出的是"changjiuhuang"。这说明,即使在函数内部修改了参数的值,但原来的引用仍然保持不变(原对象是一个全局对象)。在函数内部重新定义obj对象时,这个变量只是一个局部对象,在函数执行完成后会被销毁的。
检测类型
typeof是检测属于什么类型,而instanceof是检测属于什么引用类型(Object、Array、RegExp)。
查询标识符
当在某个环境中为了读取或写入而引用一个标识符时,必须通过搜索来确定该标识符代表什么内容。搜索过程是从作用链前端开始,向上逐级搜索与给定名字匹配的标识符,如果在局部环境中找到该标识符,则搜索结束,变量就绪。如果未在局部环境中找到,则沿着作用域链向上继续搜索,一直到全局环境的全局变量。var color = "blue";
function getColor() {
return color;
}
alert(getColor()); //弹出"blue"
调用getColor()函数会涉及到变量color,为了确定color的值,会搜索getColor()的变量对象,在局部环境中找到其中是否包含一个名为color的标识符,如果没有找到,则继续搜索到下一个变量对象(全局环境中的全局变量对象),如果搜索到了,则搜索结束,如果还是没有搜索到,说明该变量未声明。
搜索过程:在局部环境getColor()中搜索标识符,如果没有,再向全局环境中(window对象)搜索。