ECMAScirpt 变量有两种不同的数据类型:基本类型,引用类型。
基本的数据类型有:undefined,boolean,number,string,null. 基本类型的访问是按值访问的,就是说你可以操作保存在变量中的实际的值。JavaScript中除了上面的基本类型之外就是引用类型了。
区别如下:
基本类型:
- 佔用空间固定,保存在栈中
- 保存与复製的是本身
- 使用typeof检测数据类型
- 值类型
引用类型:
- 佔用空间不固定,保存在堆中
- 保存与复製的是指向对象的一个指针
- 使用instanceof检测数据类型
- 使用new()方法构造出来的对象是引用类型(相关内容可参考关於Javascript中的new运算符,构造函数与原型链一些理解)
基本类型是不会改变,衹能重新赋值,而引用类型值是可以改变的
var a = '123456789',
b = a;
a = '321';
console.log(a) // 321
console.log(b) // 123456789
上面因為是把值保存在了变量了 而不是保存的是引用地址,所以他们两个是相对独立的整体,互不影响。但是如果换成引用类型的话
var a = {
n: '123456789'
},
b = a;
a.n ='321';
console.log(a) // { n: '321' }
console.log(b) // { n: '321' }
原因在於在javascript语言中创建的对象值中其保存的是对象的引用(也就是一个地址.引用类型值保存在内存中,而JS是不能直接访问内存的,所以对於引用类型,操作的不是实际的对象而是对象的引用。)
这里有个小提示説一下,假如两个相同的基本类型或引用类型(内容一样)相比,看看结果是怎样的?
var base1 = '123',
base2 = '123',
obj1 = { a: '123' },
obj2 = { a: '123' };
console.log(base1 === base2) // true
console.log(obj1 === obj2) // false
如果你还错了那就证明你没理解透上面的东西了,因为前面是值之间直接比较,后面是指向地址的比较,即使两个引用类型看起来一样,衹要不是同一个声明变量,它们就一定不同。
知识一:基本类型值就是简单的数据段;引用类型值保存的是对象的引用,不是实际的对象。
但是在函数中的对象传值又是不是同一回事呢?看看下面代码
function setName(obj) {
obj.name = '1';
obj = {};
obj.name = '2';
}
var obj = {};
setName(obj);
console.log('最终结果obj:', obj) // 最终结果obj: { name: '1' }
没错,结果出乎意料的是1.而不是大多数人刚开始认为的2.
接下来我们在一步步分析出在函数过程中对象发生了什么样的变化?稍微修改下对象名便於区分。
function setName(innerObj) {
console.log('初始的innerObj:', innerObj); // 初始的innerObj: {}
innerObj.name = '1';
console.log('第一次设置属性值的innerObj:', innerObj); // 第一次设置属性值的innerObj: { name: '1' }
//保存下原对象
var _innerObj = innerObj;
innerObj = {};
console.log('重新赋值的innerObj:', innerObj); // 重新赋值的innerObj: {}
innerObj.name = '2';
console.log('第二次设置属性值的innerObj:', innerObj); // 第二次设置属性值的innerObj: { name: '2' }
console.log('两者之间是不是同一个对象?:', _innerObj == innerObj) // 两者之间是不是同一个对象?: false
console.log('innerObj:', innerObj) // innerObj: { name: '2' }
console.log('_innerObj: ', _innerObj) // _innerObj: { name: '1' }
}
var outerObj = {};
setName(outerObj);
console.log('最终结果outerObj:', outerObj) // 最终结果outerObj: { name: '1' }
过程中可以看出在函数中间 innerObj = {}
之后;对象的指向就已经变了,也就是说这里相当於重新建立一个新的指向,后续的操作都是基於新指向之上进行的。
此时,outerObj === _innerObj !== innerObj, 所以最终输出的是1而不是2.
如果还有些混乱的同学,看看如果不通过函数直接修改会是什么结果?
var obj = {'a':1}
obj = {};
obj = {'a':2};
console.log(obj) // { a: 2 }
这次确确实实的是输出2了。
知识二:JS中所有函数传参都是按值传递的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。