JavaScript之基本数据与引用数据的简单讨论

JavaScript有两种数据类型:基本数据、引用数据。

基本数据类型有: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对象)搜索。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值