JS基本类型与引用类型知多少

11,616 阅读5分钟

1、JavaScript值类型和引用类型有哪些

(1)值类型(基本类型):数值(number)、布尔值(boolean)、null、undefined、string(在赋值传递中会以引用类型的方式来处理)。

(2)引用类型:对象、数组、函数。

2、如何理解值类型和引用类型

之前看到一个比喻,觉得非常贴切,想要和大家分享一下:

用“连锁店”和“连锁店钥匙”来理解。

(1)值类型:变量的交换等于在一个新的地方按照连锁店的规范标准(统一店面理解为相同的变量内容)新开一个分店,这样新开的店与其它旧店互不相关、各自运营。

function str() 
{ 
var str1='Hello World'; 
var str2=str1; 
str1='Hello'; 
alert(str2); //Hello World 
} 
str();

把一个值类型(也叫基本类型)str2赋值给另一个变量时,其实是分配了一块新的内存空间,因此改变str1的值对str2没有任何影响,因为它不同于引用类型(变量的交换其实是交换了指像同一个内容的地址)。

再看一个例子:

var a = 1;
var b = a;

a ++ ;
console.log(a); // 2
console.log(b); // 1

在从一个变量向另一个变量赋值基本类型时,会在该变量上创建一个新值,然后再把该值复制到为新变量分配的位置上。

例子中,一开始,a中保存的值为 1 ,当使用 a 来初始化 b 时,b 中保存的值也为1,但b中的1与a中的是完全独立的,该值只是a中的值的一个副本,此后,这两个变量可以参加任何操作而相互不受影响,即基本类型在赋值操作后,两个变量是相互不受影响的。

这里写图片描述
这里写图片描述

(2)引用类型:变量的交换等同于把现有一间店的钥匙(变量引用地址)复制一把给了另外一个老板,此时两个老板同时管理一间店,两个老板的行为都有可能对一间店的运营造成影响。

function str() 
{ 
var str1=['Hello World']; 
var str2=str1; 
alert(str2[0]); //Hello World 
str1[0]='Hello'; 
alert(str2[0]); //Hello
} 
str();

str2只进行了一次赋值,理论上它的值已定,但后面通过改写str1的值,发现str2的值也发生了改变,这正是引用类型的特点。

再看个例子:

var a = {}; // a保存了一个空对象的实例
var b = a;  // a和b都指向了这个空对象

a.name = 'coco';
console.log(a.name); // 'coco'
console.log(b.name); // 'coco'

b.age = 24;
console.log(b.age);// 24
console.log(a.age);// 24

console.log(a == b);// true

这里写图片描述
这里写图片描述

引用类型的赋值其实是对象保存在栈区地址指针的赋值,因此两个变量指向同一个对象,任何的操作都会相互影响。

3、值类型和引用类型的区别

(1)基本类型的值是一经确定就不可变的

(2)基本类型的比较是值的比较

只有在它们的值相等的时候它们才相等。

比较的两个值的类型不同的时候==运算符会进行类型转换,但是当两个值的类型相同的时候,即使是==也相当于是===。

var a = 1;
var b = true;
console.log(a == b);//true

在用==比较两个不同类型的变量时会进行一些类型转换。如上的比较先会把true转换为数字1再和数字1进行比较,结果就是true了。

var a = 'coco';
var b = 'coco';
console.log(a === b);//true

(3)基本类型的变量是存放在栈区的(栈区指内存里的栈内存)

var name = 'coco';
var city = 'shenzhen';
var age = 24;
存储结构如下:

这里写图片描述
这里写图片描述

栈区包括了 变量的标识符和变量的值。

(4)引用类型的值是可变的

可以为引用类型添加属性和方法,也可以删除其属性和方法。

var person = {};//创建一个空对象 --引用类型
person.name = 'coco';
person.age = 24;
person.sayName = function(){
console.log(person.name);
} 
person.sayName();// 'coco'
var person = {};//创建一个空对象 --引用类型
person.name = 'coco';
person.age = 24;
person.sayName = function(){
console.log(person.name);
} 
person.sayName();// 'coco'
delete person.name; //删除person对象的name属性
person.sayName(); // undefined

引用类型可以拥有属性和方法,并且是可以动态改变的。

(5)引用类型的值是同时保存在栈内存和堆内存中的对象

js不同于其他语言,其不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间,实际上,是操作对象的引用,所以引用类型的值是按引用访问的。

准确地说,引用类型的存储需要内存的栈区和堆区(堆区是指内存里的堆内存)共同完成,栈区内存保存变量标识符和指向堆内存中该对象的指针,也可以说是该对象在堆内存的地址。

var person1 = {name:'zhangsan'};
var person2 = {name:'lisi'};
var person3 = {name:'wangwu'};

则这三个对象的在内存中保存的情况如下图:

这里写图片描述
这里写图片描述

(6)引用类型的比较是引用的比较

var person1 = '{}';
var person2 = '{}';
console.log(person1 == person2); // true

基本类型的比较--当两个比较值的类型相同的时候,相当于是用 === ,所以输出是true。

var person1 = {};
var person2 = {};
console.log(person1 == person2); // false

上面比较的是两个字符串,而下面比较的是两个对象,为什么长的一模一样的对象就不相等了呢?

引用类型是按引用访问,换句话说就是比较两个对象的堆内存中的地址是否相同,那很明显,person1和person2在堆内存中地址是不同的:

这里写图片描述
这里写图片描述

这两个是完全不同的对象,所以返回false。