首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >重学JS基础--数据类型

重学JS基础--数据类型

作者头像
Jou
发布2022-08-10 20:50:54
发布2022-08-10 20:50:54
9970
举报
文章被收录于专栏:前端技术归纳前端技术归纳

一.基本数据类型

js有5大基本数据类型包括:

  • undefined
  • null
  • number
  • boolean
  • string
  • ES6新增了一种基本数据类型Symbol(用于标识唯一性)

这些数据是直接存在栈空间中的,基本数据类型是按值访问的,就是说我们可以操作保存在变量中的实际的值。

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

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

代码语言:javascript
复制
var name = "change";
name.substr();//hang
console.log(name);//change

var s = "hello";
s.toUpperCase()//HELLO;
console.log(s)//hello

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

假如我们直接赋值改变呢,看代码:

代码语言:javascript
复制
var name = "change";
name = "change1";
console.log(name)//change1

这样看起来name的值“改变了” 其实,var name = "change",这里的基础类型是string,也就是"change",这里的"change"是不可以改变的

name只是指向"change"的一个指针,指针的指向可以改变,所以你可以name = "change1".此时name指向了"change1",同理,这里的"change1"同样不可以改变.

也就是说这里你认为的改变只是“指针的指向改变”,这里的基础类型指的是"change",而不是name,要区分清楚

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

代码语言:javascript
复制
var p = "change";
p.age = 29;
p.method = function(){console.log(name)};
console.log(p.age)//undefined
console.log(p.method)//undefined

通过上面的代码,我们知道不能给基本类型添加属性和方法。

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

代码语言:javascript
复制
var person1 = '{}';
var person2 = '{}';
console.log(person1 == person2); // true

二.引数据类型

js中除了上面的基本类型之外就是引用类型了,也可以说就是对象了,Object,Function等(这里注意,Array.Date都被归为了Object类型),它们在栈空间中存的是一个指针,指向的是存在堆空间里面的值。

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

代码语言:javascript
复制
var o = {x:1};
o.x = 2;//通过修改对象属性值更改对象
o.y = 3;//再次更改对象,给它增加一个属性

var a = [1,2,3];
a[0] = 0;//更改数组的一个元素
a[3] = 4;//给数组增加一个元素

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

代码语言:javascript
复制
var person = {};
person.name = "change";
person.say = function(){alert("hello");}
console.log(person.name)//change
console.log(person.say)//function(){alert("hello");}

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

先看以下代码:

代码语言:javascript
复制
var a = {};
var b= a;
a.name = "change";
console.log(a.name)//change;
console.log(b.name)//change
b.age = 29;
console.log(a.age)//29
console.log(b.age)//29

当从一个变量向另一个变量赋值引用类型的值时,同样也会将储存在变量中的对象的值复制一份放到为新变量分配的空间中.引用类型保存在变量中的是对象在堆内存中的地址。

所以,与基本数据类型的简单赋值不同,这个值的副本实际上是一个指针,而这个指针指向存储在堆内存的一个对象.那么赋值操作后,两个变量都保存了同一个对象地址,而这两个地址指向了同一个对象.因此,改变其中任何一个变量,都会互相影响。

引用类型的比较是引用的比较
代码语言:javascript
复制
var person1 = {};
var person2 = {};
console.log(person1 == person2)//false

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

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

三.基本包装类型(包装对象):

先看下以下代码:

代码语言:javascript
复制
var s1 = "helloworld";
var s2 = s1.substr(4);

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

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

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

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

代码语言:javascript
复制
var s1 = new String("helloworld");  //创建String类型的一个实例;
var s2 = s1.substr(4);          //在实例上调用指定方法;
s1 = null;                      //销毁这个实例;

正因为有第三步这个销毁的动作,所以你应该能够明白为什么基本数据类型不可以添加属性和方法,这也正是基本装包类型和引用类型主要区别:对象的生存期

  • 使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都是一直保存在内存中
  • 而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁.

四.常见问题梳理

undefind,null,NaN,void 0比较

underfind :缺少值,此处应该有一个值,转化为数字后变成 NaN

null : 定义了但是为空,转化为数字化后变成0

void 0 : 等于undefined

NaN : 代表非数字值的特殊值。该属性用于指示某个值不是数字。

代码语言:javascript
复制
		console.log("undefined == null", undefined == null);     //true
		console.log("{} == {}", {} == {});                       //false
		console.log("NaN == NaN", NaN == NaN);                   //false
		console.log("0 == undefined", 0 == undefined);           //false
		console.log("void 0 == null", void 0 == null);           //true

为何使用void 0取代undefined?

注意 : void是一元运算符,出现在操作数的左边,操作数可以是任意类型的值,void右边的表达式可以是带括号形式(例如:void(0)),也可以是不带括号的形式(例如:void 0)。

  • 在ES5的全局环境中,undefined是只读的。而在局部作用域中,undefined是可变的,所以推荐使用void 0获取undefind。
  • 使用void 0比使用undefined能够减少3个字节
代码语言:javascript
复制
>"undefined".length
//9
>"void 0".length
//6

undefined并不是javascript中的保留字,我们可以使用undefined作为变量名字,然后给它赋值。void 0输出唯一的结果undefined,保证了不变性。

为何 0.1+0.2 == 0.3 为false?

JS 数字类型只有number类型,number类型相当于其他强类型语言中的double类型(双精度浮点型),不区分浮点型和整数型。

由于Js的所有数字类型都是双精度浮点型(64位)采用 IEEE754 标准 64位二进制数表示一个number数字

其中 64位 = 1位符号位 + 11位指数位 + 52位小数位

浮点数的运算精度丢失问题就是因为,浮点数转化为该标准的二进制的过程中,并不能直接转化,只能转化为一个近似的值,所以有精度的丢失

推荐解决办法

  • 将小数的运算转化为整数的运算,使用Math.floor():向下取整,Math.ceil():向上取整
  • 检测最小精度差 console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);

如何检测+0和-0?

除了NaN,JS还有两个特殊的数字

  • Infinity,无穷大;
  • -Infinity,负无穷大。

JavaScript 中有 +0 和 -0,在加法类运算中它们没有区别,但是除法的场合则需要特别留意区分。 “忘记检测除以 -0,而得到负无穷大”的情况经常会导致错误,

而区分 +0 和 -0 的方式,正是检测 1/x 是 Infinity 还是 -Infinity。

字符串的最大长度是多少?

String 用于表示文本数据。String 有最大长度是 2^53 - 1,这在一般开发中都是够用的,

但是有趣的是,这个所谓最大长度,并不完全是你理解中的字符数。因为 String 的意义并非“字符串”,而是字符串的 UTF16 编码,我们字符串的操作 charAt、charCodeAt、length 等方法针对的都是 UTF16 编码。所以,字符串的最大长度,实际上是受字符串的编码长度影响的。

代码语言:javascript
复制
Note:现行的字符集国际标准,字符是以 Unicode 的方式表示的,
每一个 Unicode 的码点表示一个字符,
理论上,Unicode 的范围是无限的。
UTF 是 Unicode 的编码方式,规定了码点在计算机中的表示方法,
常见的有 UTF16 和 UTF8。 Unicode 的码点通常用 U+??? 来表示,
其中 ??? 是十六进制的码点值。 
0-65536(U+0000 - U+FFFF)的码点被称为基本字符区域(BMP)。

也就是说length并不是直接返回直觉上字符串的长度,而是返回在Unicode编码状态下编码码点的长度。

比如说一个韩文字符的length是2。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-07-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.基本数据类型
    • 基本数据类型的值是不可变的
    • 基本数据类型不可以添加属性和方法
    • 基本数据类型的比较是值的比较
  • 二.引数据类型
    • 引用类型的值是可以改变的
    • 引用类型可以添加属性和方法
    • 引用类型的赋值是对象引用
      • 引用类型的比较是引用的比较
  • 三.基本包装类型(包装对象):
  • 四.常见问题梳理
    • undefind,null,NaN,void 0比较
    • 为何使用void 0取代undefined?
    • 为何 0.1+0.2 == 0.3 为false?
    • 如何检测+0和-0?
    • 字符串的最大长度是多少?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档