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引擎通过在内部临时创建一个对应的包装类型的临时对象,并把对基本类型的操作代理到这个临时对象身上,使得对基本类型的属性访问看起来像对象一样。但是在操作完成后,临时对象就扔掉了,下次再访问时,会重新建立临时对象,当然对之前的临时对象的修改都不会有效。)。

相关文章
|
23天前
|
存储 Java 对象存储
String 属于基础的数据类型吗
String 在多数编程语言中被视为一种基础数据类型,但实际上它是由字符组成的序列。在一些语言中,如 Java 和 Python,String 被设计为不可变的对象,以简化编程和提高安全性。
31 5
|
25天前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
1月前
|
监控 JavaScript 前端开发
确定使用 `defer` 属性还是 `async` 属性来异步加载 JavaScript
【10月更文挑战第24天】选择使用 `defer` 属性还是 `async` 属性来异步加载 JavaScript 是一个需要综合考虑多个因素的决策。需要根据脚本之间的依赖关系、页面加载性能要求、脚本的功能和重要性等因素来进行权衡。在实际应用中,需要通过测试和验证来确定最适合的加载方式,以提供更好的用户体验和页面性能。
|
23天前
|
Java
在Java中如何将基本数据类型转换为String
在Java中,可使用多种方法将基本数据类型(如int、char等)转换为String:1. 使用String.valueOf()方法;2. 利用+运算符与空字符串连接;3. 对于数字类型,也可使用Integer.toString()等特定类型的方法。这些方法简单高效,适用于不同场景。
47 7
|
25天前
|
安全
String、StringBuffer、StringBuilder的区别
String 由 char[] 数组构成,使用了 final 修饰,对 String 进行改变时每次都会新生成一个 String 对象,然后把指针指向新的引用对象。 StringBuffer可变并且线程安全;有一定缓冲区容量,字符串大小没超过容量,不会重新分配新的容量,适合多线程操作字符串; StringBuiler可变并且线程不安全。速度比StringBuffer更快,适合单线程操作字符串。 操作少量字符数据用 String;单线程操作大量数据用 StringBuilder;多线程操作大量数据用 StringBuffer
|
1月前
|
监控 JavaScript 前端开发
使用 `defer` 属性异步加载 JavaScript
【10月更文挑战第24天】使用 `defer` 属性异步加载 JavaScript 是一种有效的提高页面性能和用户体验的方法。通过合理设置 `defer` 属性,可以在不影响页面渲染的情况下异步加载脚本,并确保脚本的执行顺序。在实际应用中,需要根据具体情况选择合适的加载方式,并注意处理可能出现的问题,以确保页面能够正常加载和执行。
|
2月前
|
移动开发 JavaScript 前端开发
原生js如何获取dom元素的自定义属性
原生js如何获取dom元素的自定义属性
76 4
|
2月前
|
存储 安全 Java
String、StringBuffer 和 StringBuilder 的区别
【10月更文挑战第21天】String、StringBuffer 和 StringBuilder 都有各自的特点和适用场景。了解它们之间的区别,可以帮助我们在编程中更合理地选择和使用这些类,从而提高程序的性能和质量。还可以结合具体的代码示例和实际应用场景,进一步深入分析它们的性能差异和使用技巧,使对它们的理解更加全面和深入。
38 0
|
2月前
|
存储 JavaScript 前端开发
js中map属性
js中map属性
22 0
|
6月前
|
前端开发 JavaScript 程序员
探索JavaScript宝库:打开基础知识与实用技能之门(数据类型与变量+ 条件与循环+函数与模块+DOM+异常+ES6)
探索JavaScript宝库:打开基础知识与实用技能之门(数据类型与变量+ 条件与循环+函数与模块+DOM+异常+ES6)
34 0