木灵鱼儿

木灵鱼儿

阅读:441

最后更新:2020/12/20/ 22:39:31

JavaScript类型:关于类型,有哪些你不知道的细节?

Undefined 为什么有的编程规范要求用void 0代替undefined?

因为在js里面,undefined是一个变量,它奴属于window,是全局对象window的一个属性。

但是全局的undefined是无法被修改的,这也意味着在局部作用域中我们可以重新定义undefined变量

function test() {
  var undefined = "我被重新定义了";

  const a = undefined;
  console.log(a);
}

test();   //我被重新定义了

这种情况只有在我们直接使用undefined变量的时候才会出现。

function test() {
  var undefined = "我被重新定义了";

  const a = {};
  console.log(a.sss);
}

test();   //undefined

在不使用undefined变量的时候,即便重定义了,也不影响返回的值是undefined。

所以,如果要使用undefined变量,一般会要求使用void 0来表示。

String 字符串有最大长度吗?

答案是有的,String的最大长度是2^53 - 1,在一般开发中都是够用的, 但是这个所谓的最大长度,并不是字符数的数量,而是UTF16编码的长度。

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

也就是说,一个utf16编码单元被认为是一个字符length,这个编码单元的范围就是基本字符区域BMP,而超出BMP范围的那些“特殊字符”,虽然是一个字,但会被识别为两个字符length或者更多,所以需要注意下这部分。

而且,字符串一但被创建,他的字符值是不可变的。

简答点来理解,你不能像对象那样,修改里面的某个值。

var test = "我是一个文本";

test[0] = "不";

console.log(test); //我是一个文本

我们无法修改字符串的各个字符,但是并不意味着test不能改变,我们可以重新赋值改变他的值。

test = "xxx";
console.log(test); //xxx

Number 0.1 + 0.2不是等于0.3么?为什么JavaScript里不是这样的?

javascript中的Number类型表示我们通常意义上的“数字”。这个数字大致对应数学中的有理数。

JavaScript中的Number类型有 18437736874454810627(即2^64-2^53+3) 个值

JavaScript 中的 Number 类型基本符合 IEEE 754-2008 规定的双精度浮点数规则,但是JavaScript为了表达几个额外的语言场景(比如不让除以0出错,而引入了无穷大的概念),规定了几个例外情况:

  • NaN,占用了 9007199254740990,这原本是符合IEEE规则的数字
  • Infinity,无穷大;
  • -Infinity,负无穷

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

也就是说在除法里面,除以正负0会得到正负无限大,这个值还是有区别的。

那么判断是正0还是负0,用1除以它,看看结果是 Infinity 还是 -Infinity

根据双精度浮点数的定义,Number类型中有效的整数范围是-0x1fffffffffffff至0x1fffffffffffff,所以Number
无法精确表示此范围外的整数。

同样根据浮点数的定义,非整数的Number类型无法用=====也不行) 来比较,一段著名的代码,这也正
是我们第三题的问题,为什么在JavaScript中,0.1+0.2不能=0.3:

console.log( 0.1 + 0.2 == 0.3)  //false

原因是因为浮点数运算的精度问题导致左右两边的结果相差微小的值,所以无法相等,全等。

当然,这种判断方式其实是错的,因为浮点数的精度问题,所以使用这种方法并不能成功判断,在es6中Numbner有一个最小精度EPSILON

onsole.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON); //true

这种方式才是正确的比较方法。

Object 为什么给对象添加的方法能用在基本类型上?

❝ JavaScript 中的几个基本类型,都在对象类型中有一个“亲戚”。它们是:Number;String;Boolean;Symbol。

  1. 我们必须认识到 3 与 new Number(3) 是完全不同的值,它们一个是 Number 类型, 一个是对象类型。
  2. Number、String 和 Boolean,三个构造器是两用的,当跟 new 搭配时,它们产生对象,当直接调用时,它们表示强制类型转换。
  3. Symbol 函数比较特殊,直接用 new 调用它会抛出错误,但它仍然是 Symbol 对象的构造器。
console.log("abc".charAt(0)); //a

Symbol.prototype.hello = () => console.log("hello");

var a = Symbol("a");
console.log(typeof a); //symbol,a并非对象
a.hello(); // hello,有效

所以这里总结答案就是 . 运算符提供了装箱操作,它会根据基础类型构造一个临时对象,使得我们能在基础类型上调用对应对象的方法。

装箱操作

默认字符串,数字这种原始值是没有方法的,他就是一个值,但是js中,我们可以在原始值上使用方法,比如:

"1".length;  //1

length方法应该是是String对象上的,而我们的.实际上提供装箱操作,他创建了一个临时的String对象,然后使用了length方法,所以我们可以这么理解上面这段代码

"1";
new String("1").length;

.点操作隐式装箱了一个String对象。

而且我们要知道"1"new String("1")是两个不同的东西,他们是不相等的。一个是String类型,一个是对象类型。

每一种基本类型 Number、String、Boolean、Symbol 在对象中都有对应的类,所谓装箱转换,正是把基本类型转换为对应的对象。

拆箱操作

既然基本类型转换为对象类型是封箱操作,那么对象类型转换为基本类型就是拆箱操作。

比如:

var b = {};

console.log(b+""); //undefined

js对象类型转基本类型,它是有规则的:

在 JavaScript 标准中,规定了 ToPrimitive 函数,它是对象类型到基本类型的转换(即,拆箱转换)。

假设函数形式如下:toPrimitive( input, preferedType ) input是输入的值,preferedType是期望转换的类型,他可以是字符串,也可以是数字。

如果转换的类型是number,会执行以下步骤:

1、 如果input是原始值,直接返回这个值;

2、 否则如果input是对象,调用input.valueOf(),如果结果是原始值,返回结果;

3、 否则,调用input.toString()。如果结果是原始值,返回结果;

4、 否则,抛出错误。

注意:如果转换的类型是String,2和3会交换执行,即先执行toString()方法。

简单点来说,在处理b+""的时候,会先运行b对象的方法,valueOf()、toString(),如果其中有一个方法返回了内容,那么就使用这个返回的内容进行+""运算。

然后根据转换类型不同,valueOf()、toString()方法会有先后顺序。

String(b);

这里就明确说明,b要进行string转换,所以拆箱是会先执行toString方法。

我们甚至可以改写这个方法,以便更明确的了解:

var o = {
  valueOf : () => {
    console.log("valueOf"); 
    return {};
  },
  toString : () => {
    console.log("toString"); 
    return {};
  }
}

String(o);

//toString
//valueOf
//TypeError

如果两个方法都没有返回基本类型,就会TypeError报错。

在 ES6 之后,还允许对象通过显式指定 @@toPrimitive Symbol 来覆盖原有的行为。

var o = {
  valueOf : () => {
    console.log("valueOf"); 
    return {};
  },
  toString : () => {
    console.log("toString"); 
    return {};
  }
}

o[Symbol.toPrimitive] = () => {
  console.log("toPrimitive"); 
  return "hello";
}

String(o);

// toPrimiti
// hel

版权申明

本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。

关于作者

站点职位 博主
获得点赞 0
文章被阅读 441

相关文章