JavaScript】基本数据类型与引用数据类型区别(及为什么String、Boolean、Number基本数据类型会有属性和方法?)

简介: JavaScript】基本数据类型与引用数据类型区别(及为什么String、Boolean、Number基本数据类型会有属性和方法?)

基本数据类型

  JavaScript基本数据类型包括:undefined、null、number、boolean、string。基本数据类型是按值访问的,就是说我们可以操作保存在变量中的实际的值。

1)基本数据类型的值是不可变的

任何方法都无法改变一个基本类型的值,比如一个字符串

var name = "change";
  name.substr();//hang
  console.log(name);//change
  var s = "hello";
  s.toUpperCase()//HELLO;
  console.log(s)//hello
• 1
• 2
• 3
• 4
• 5
• 6
• 7

通过这两个例子,我们会发现原先定义的变量name的值始终没有发生改变,而调用substr()和toUpperCase()方法后返回的是一个新的字符串,跟原先定义的变量name并没有关系。

或许有人会有以下的疑问,看代码:

var name = "change";
  name = "change1";
  console.log(name)//change1
• 1
• 2
• 3

这样看起来name的值“改变了”其实,var name = “change”,这里的基础类型是string,也就是”change”,这里的”change”是不可以改变的,name只是指向”change”的一个指针,指针的指向可以改变,所以你可以name = “change1″.此时name指向了”change1″,同理,这里的”change1″同样不可以改变。也就是说这里你认为的改变只是“指针的指向改变”

2)基本数据类型不可以添加属性和方法

var p = "change";
  p.age = 29;
  p.method = function(){console.log(name)};
  console.log(p.age)//undefined
  console.log(p.method)//undefined
• 1
• 2
• 3
• 4
• 5

3)基本数据类型的赋值是简单赋值

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

var a = 10;
var b = a;
a++;
console.log(a)//11
console.log(b)//10
• 1
• 2
• 3
• 4
• 5

上面的代码中,a中保存的值是10.当使用a的值来初始化b时,b中也保存了值10。但b中的10和a中的10是完全独立的。b中的值只是a中值的一个副本.所以这两个变量可以参与任何操作而不会相互影响。

4)基本数据类型的比较是值的比较

var person1 = '{}';
var person2 = '{}';
console.log(person1 == person2); // true
• 1
• 2
• 3

5)基本数据类型是存放在栈区的

假如有以下几个基本类型的变量:

var name = "jozo";
var city = "guangzhou";
var age = 22;
• 1
• 2
• 3

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

引用数据类型

  JavaScript中除了基本数据类型外就是引用数据类型了(也可以说是对象)。比如:Object、Array、Function、Data等。

1)引用类型的值是可以改变的

var o = {x:1};
o.x = 2;  // 通过修改对象属性值更改对象
o.y = 3;  // 再次更改对象,给它增加一个属性
var a = [1,2,3];
a[0] = 0; // 更改数组的一个元素
a[3] = 4; // 给数组增加一个元素
• 1
• 2
• 3
• 4
• 5
• 6
• 7

2)引用类型可以添加属性和方法

var person = {};
person.name = "change";
person.say = function(){alert("hello");}
console.log(person.name)//change
console.log(person.say)//function(){alert("hello");}
• 1
• 2
• 3
• 4
• 5

3)引用类型的赋值是对象引用

1.var a = {};
  2.var b= a;
  3.a.name = "change";
  4.console.log(a.name)//change;
  5.console.log(b.name)//change
  6.b.age = 29;
  7. console.log(a.age)//29
  8. console.log(b.age)//29
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8

当从一个变量向另一个变量赋值引用类型的值时,同样也会将储存在变量中的对象的值复制一份放到为新变量分配的空间中.引用类型保存在变量中的是对象在堆内存中的地址,所以,与基本数据类型的简单赋值不同,这个值的副本实际上是一个指针,而这个指针指向存储在堆内存的一个对象。那么赋值操作后,两个变量都保存了同一个对象地址,而这两个地址指向了同一个对象。因此,改变其中任何一个变量,都会互相影响。

4)引用类型的比较是引用的比较

1.var person1 = {};
  2.var person2 = {};
  3.console.log(person1 == person2)//false
• 1
• 2
• 3

为什么两个对象看起来一摸一样,但是却不相等呢?

因为引用类型的比较是引用的比较,换句话说,就是比较两个对象保存在栈区的指向堆内存的地址是否相同,此时,虽然p1和p2看起来都是一个”{}”,但是他们保存在栈区中的指向堆内存的地址却是不同的,所以两个对象不相等

5)引用类型是同时保存在栈区和堆区中的

引用类型的存储需要在内存的栈区和堆区共同完成,栈区保存变量标识符和指向堆内存的地址

假如有以下几个对象:

1.var person1 = {name:"change1"};
  2.var person2 = {name:"change2"};
  3.var person3 = {name:"change3"};
• 1
• 2
• 3

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

基本包装类型(包装对象)

先看下以下代码:

1 var s1 = "helloworld";
 2. var s2 = s1.substr(4);
• 1
• 2

上面我们说到字符串是基本数据类型,不应该有方法,那为什么这里s1可以调用substr()呢?

通过翻阅JavaScript权威指南第3.6章节和高级程序设计第5.6章节我们得知,ECMAScript还提供了三个特殊的引用类型Boolean、String、Number,我们称这三个特殊的引用类型为基本包装类型,也叫包装对象。

通过字面量的方式创建:var a = “String”; 这时它是基本数据类型;

通过构造函数的方式创建:var a = new String(“String”); 这时它是对 象类型。

也就是说当读取string、boolean和number这三个基本数据类型的时候,后台就会创建一个对应的基本包装类型对象,从而让我们能够调用一些方法来操作这些数据。

所以当第二行代码访问s1的时候,后台会自动完成下列操作:

1  创建String类型的一个实例;// var s1 = new String(“helloworld”);
2 在实例上调用指定方法;// var s2 = s1.substr(4);
3  销毁这个实例;// s1 = null;
• 1
• 2
• 3

正因为有第三步这个销毁的动作,所以你应该能够明白为什么基本数据类型不可以添加属性和方法,这也正是基本包装类型和引用类型主要区别:对象的生存期。使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都是一直保存在内存中.而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁(说的详细一点就是,JS引擎通过在内部临时创建一个对应的包装类型的临时对象,并把对基本类型的操作代理到这个临时对象身上,使得对基本类型的属性访问看起来像对象一样。但是在操作完成后,临时对象就扔掉了,下次再访问时,会重新建立临时对象,当然对之前的临时对象的修改都不会有效。)。

相关文章
|
8天前
|
存储 JavaScript 索引
js开发:请解释什么是ES6的Map和Set,以及它们与普通对象和数组的区别。
ES6引入了Map和Set数据结构。Map的键可以是任意类型且有序,与对象的字符串或符号键不同;Set存储唯一值,无重复。两者皆可迭代,支持for...of循环。Map有get、set、has、delete等方法,Set有add、delete、has方法。示例展示了Map和Set的基本操作。
19 3
|
9天前
|
JavaScript 前端开发
js开发:请解释原型继承和类继承的区别。
JavaScript中的原型继承和类继承用于共享对象属性和方法。原型继承通过原型链实现共享,节省内存,但不支持私有属性。
17 0
|
1天前
|
安全
String、StringBuuffer、StringBuilder三者的区别
String、StringBuuffer、StringBuilder三者的区别
|
2天前
|
前端开发 JavaScript
【Web 前端】 js中call、apply、bind有什么区别?
【4月更文挑战第22天】【Web 前端】 js中call、apply、bind有什么区别?
【Web 前端】 js中call、apply、bind有什么区别?
|
2天前
|
存储 前端开发 JavaScript
【Web 前端】JS数据类型有哪些?区别?
【4月更文挑战第22天】【Web 前端】JS数据类型有哪些?区别?
|
5天前
|
JavaScript 前端开发
js的let、const、var的区别以及应用案例
【4月更文挑战第27天】ES6 中,`let` 和 `const` 是新增的变量声明关键字,与 `var` 存在显著差异。`let` 允许重新赋值,而 `const` 不可,且两者都具有块级作用域。`var` 拥有函数级作用域,并可在函数内任意位置访问。`let` 和 `const` 声明时必须初始化,而 `var` 不需。根据需求选择使用:局部作用域用 `let`/`const`,全局或函数范围用 `var`,不可变值用 `const`。
14 2
|
6天前
|
JSON JavaScript 前端开发
vue2_vite.config.js的proxy跨域配置和nginx配置代理有啥区别?
vue2_vite.config.js的proxy跨域配置和nginx配置代理有啥区别?
21 1
|
7天前
|
JavaScript 前端开发 Oracle
java和JavaScript的区别
java和JavaScript的区别
7 3
|
8天前
|
存储 安全 Java
面试官:请聊一聊String、StringBuilder、StringBuffer三者的区别
面试官:请聊一聊String、StringBuilder、StringBuffer三者的区别
36 8
|
8天前
|
C++
【C++】std::string 转换成非const类型 char* 的三种方法记录
【C++】std::string 转换成非const类型 char* 的三种方法记录
5 0

热门文章

最新文章