JavaScript数据类型

数据类型

1.JavaScript有哪些数据类型,它们的区别?

JavaScript共有八种数据类型,分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。

其中 Symbol 和 BigInt 是ES6 中新增的数据类型:
● Symbol 代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。
● BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。

这些数据可以分为原始数据类型和引用数据类型:
● 栈:原始数据类型(Undefined、Null、Boolean、Number、String、Symbol、BigInt)
● 堆:引用数据类型(对象、数组和函数)

基本数据类型的修改实际上是新申请一块内存地址,将这个指针指向新的内存地址。使用const定义变量,实际上相当于定义了一个指针常量,指向固定的地址不能被修改。

引用类型修改时相当于前拷贝,内存地址不发生变化

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

var a ={};
var b = a;
a.name = 'Mary';
console.log(a.name); //'Mary'
console.log(b.name);//'Mary'
 
b.age = 22;
console.log(b.age); //22
console.log(a.age); //22
console,.log(a==b);  //true

在这里插入图片描述
两种类型的区别在于存储位置的不同:
● 原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;
● 引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:
● 在数据结构中,栈中数据的存取方式为先进后出。
● 堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。

在操作系统中,内存被分为栈区和堆区:
● 栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
● 堆区内存一般由开发着分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收。

2. 数据类型检测的方式有哪些

(1)typeof

console.log(typeof 2);               // number
console.log(typeof true);            // boolean
console.log(typeof 'str');           // string
console.log(typeof []);              // object    
console.log(typeof function(){});    // function
console.log(typeof {});              // object
console.log(typeof undefined);       // undefined
console.log(typeof null);            // object

其中数组、对象、null都会被判断为object,其他判断都正确。

(2)instanceof

instanceof可以正确判断对象的类型,其内部运行机制是判断在其原型链中能否找到该类型的原型。

console.log(2 instanceof Number);                    // false
console.log(true instanceof Boolean);                // false 
console.log('str' instanceof String);                // false 
 
console.log([] instanceof Array);                    // true
console.log(function(){} instanceof Function);       // true
console.log({} instanceof Object);                   // true

instanceof只能正确判断引用数据类型,而不能判断基本数据类型。

(3) constructor

console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true

constructor有两个作用,一是判断数据的类型,二是对象实例通过 constrcutor 对象访问它的构造函数。需要注意,如果创建一个对象来改变它的原型,constructor就不能用来判断数据类型了:

function Fn(){};
 
Fn.prototype = new Array();
 
var f = new Fn();
 
console.log(f.constructor===Fn);    // false
console.log(f.constructor===Array); // true

(4)Object.prototype.toString.call()

Object.prototype.toString.call() 使用 Object 对象的原型方法 toString 来判断数据类型:

var a = Object.prototype.toString;
 
console.log(a.call(2));
console.log(a.call(true));
console.log(a.call('str'));
console.log(a.call([]));
console.log(a.call(function(){}));
console.log(a.call({}));
console.log(a.call(undefined));
console.log(a.call(null));

同样是检测对象obj调用toString方法,obj.toString()的结果和Object.prototype.toString.call(obj)的结果不一样

  console.log(function () {}.toString());
  //function () {}
  

这是因为toString是Object的原型方法,而Array、function等类型作为Object的实例,都重写了toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串…),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object原型上的toString方法。

3. 判断数组的方式有哪些

● 通过Object.prototype.toString.call()做判断

 <script>
      function fn() {
        console.log("11");
      }
      console.log(Object.prototype.toString.call(fn)); //”[object Function]”);//”[object Function]”
	
      var obj = [1, 2, 3];
      //通过Object.prototype.toString.call()做判断
      console.log(Object.prototype.toString.call(obj).slice(8, -1) === "Array"); //true
      //通过原型链做判断
      console.log(obj.__proto__ === Array.prototype);//true
      //通过ES6的Array.isArray()做判断
      console.log(Array.isArray(obj));//true
      //通过instanceof做判断
      console.log(obj instanceof Array);//true
      //通过Array.prototype.isPrototypeOf
      console.log(Array.prototype.isPrototypeOf(obj));//true
    </script>

4. null和undefined区别

1、概念

undefined 表示未定义,就是应该有值但是还没有赋值,连null的值都没有赋予

null 代表空值,空引用。

2、区别

  1. null 和 undefined 虽然值的结果是相等的,但是其所代表的语义是完全不一样的(==是相等的)。

undefined 代表了某个变量完全不存在,在内存中完全能不存在这个标识符所指向的地址;

null 代表了内存中是存在这个变量的,只是我在某些情况下需要把这个变量原本的值给覆盖了,将它设置为一个空。

  1. null 转为数值是 0 ; undefined 转为数值是 NAN(not a number)。

  2. null 通过 typeof 判断类型的时候结果的输出是 object ; 而 undefined 的类型是 undefined 。

那么为什么 typeof null 是 object ?

null 和 undefined 都是js语言的基础数据类型, 都是原始值类型,但是 typeof null 是 object ,是因为不同的对象在底层都表现为二进制,在 JavaScript 中二进制前三位都为 0 的话会被判断为 object 类型,null 的二进制全部都为 0 ,前三位自然也是 0 ,所以执行 typeof 值会返回 object 。

  1. null 是 js 语言的关键字,是不允许用户用来作为标识符声明变量的,但是 undefined 可以,undefined 不是关键字。

在 node 环境中,我们声明的 undefined 会将原本的 undefined 覆盖的,但是在浏览器环境中不会,是因为浏览器中的 undefined 是直接被使用 Object.defineProperty 定义在了全局对象 window 上,默认就已经被配置成为了:值不可修改并且不可以被重新进行配置。

3、null 和 undefined分别在实际项目中出现的场景有哪些

1、 undefined

a. 变量被声明了,但是没有被赋值;

b. 调用函数的时候,应该给函数传参却没有给函数传这个参数打印出来就是 undefined;

c. 访问一个对象中没有的属性;

d. 函数没有返回值时,默认就会返回undefined。

2、 null

a.作为对象原型链的终点出现;

b.当我们访问一个不存在的dom节点的时候。

5. typeof null 的结果是什么,为什么?

typeof null 的结果是Object。

javascript中不同对象在底层都表示为二进制,而javascript 中把二进制前三位都为0的判断为object类型,而null的二进制表示全都是0,自然前三位也是0,所以执行typeof时会返回’object’

在 JavaScript 第一个版本中,所有值都存储在 32 位的单元中,每个单元包含一个小的 类型标签(1-3 bits) 以及当前要存储值的真实数据。类型标签存储在每个单元的低位中,共有五种数据类型:

000: object   - 当前存储的数据指向一个对象。
  1: int      - 当前存储的数据是一个 31 位的有符号整数。
010: double   - 当前存储的数据指向一个双精度的浮点数。
100: string   - 当前存储的数据指向一个字符串。
110: boolean  - 当前存储的数据是布尔值。

如果最低位是 1,则类型标签标志位的长度只有一位;如果最低位是 0,则类型标签标志位的长度占三位,为存储其他四种数据类型提供了额外两个 bit 的长度。

有两种特殊数据类型:
● undefined的值是 (-2)30(一个超出整数范围的数字);
● null 的值是机器码 NULL 指针(null 指针的值全是 0)

那也就是说null的类型标签也是000,和Object的类型标签一样,所以会被判定为Object。

6. intanceof 操作符的实现原理及实现

instanceof 运算符用于判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。

function myInstanceof(left, right) {
  // 获取对象的原型
  let proto = Object.getPrototypeOf(left)
  // 获取构造函数的 prototype 对象
  let prototype = right.prototype; 
 
  // 判断构造函数的 prototype 对象是否在对象的原型链上
  while (true) {
    if (!proto) return false;
    if (proto === prototype) return true;
    // 如果没有找到,就继续从其原型上找,Object.getPrototypeOf方法用来获取指定对象的原型
    proto = Object.getPrototypeOf(proto);
  }
}

7. 为什么0.1+0.2 ! == 0.3,如何让其相等

<script>
      let n1 = 0.1,
        n2 = 0.2;
      console.log(n1 + n2); // 0.30000000000000004
      console.log((n1 + n2).toFixed(2)); // 注意,toFixed为四舍五入
    </script>

计算机是通过二进制的方式存储数据的,所以计算机计算0.1+0.2的时候,实际上是计算的两个数的二进制的和。0.1的二进制是0.0001100110011001100…(1100循环),0.2的二进制是:0.00110011001100…(1100循环),这两个数的二进制都是无限循环的数。那JavaScript是如何处理无限循环的二进制小数呢?

一般我们认为数字包括整数和小数,但是在 JavaScript 中只有一种数字类型:Number,它的实现遵循IEEE 754标准,使用64位固定长度来表示,也就是标准的double双精度浮点数。在二进制科学表示法中,双精度浮点数的小数部分最多只能保留52位,再加上前面的1,其实就是保留53位有效数字,剩余的需要舍去,遵从“0舍1入”的原则。

根据这个原则,0.1和0.2的二进制数相加,再转化为十进制数就是:0.30000000000000004。

下面看一下双精度数是如何保存的:

● 第一部分(蓝色):用来存储符号位(sign),用来区分正负数,0表示正数,占用1位
● 第二部分(绿色):用来存储指数(exponent),占用11位
● 第三部分(红色):用来存储小数(fraction),占用52位

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3

function numberepsilon(arg1,arg2){                   
  return Math.abs(arg1 - arg2) < Number.EPSILON;        
}        

console.log(numberepsilon(0.1 + 0.2, 0.3)); // true

8. 如何获取安全的 undefined 值?

因为 undefined 是一个标识符,所以可以被当作变量来使用和赋值,但是这样会影响 undefined 的正常判断。表达式 void ___ 没有返回值,因此返回结果是 undefined。void 并不改变表达式的结果,只是让表达式不返回值。因此可以用 void 0 来获得 undefined。

9. typeof NaN 的结果是什么?

NaN 指“不是一个数字”(not a number),NaN 是一个“警戒值”(sentinel value,有特殊用途的常规值),用于指出数字类型中的错误情况,即“执行数学运算没有成功,这是失败后返回的结果

typeof NaN; // "number"

NaN 是一个特殊值,它和自身不相等,是唯一一个非自反(自反,reflexive,即 x === x 不成立)的值。而 NaN !== NaN 为 true。

10.isNaN 和 Number.isNaN 函数的区别

NaN
NaN意指“not a number“,是一个“警戒值”,用于指出数字类型中的错误情况。
typeof NaN的返回值是”number“。
NaN是一个特殊值,它与自身不相等,是唯一一个非自反的值。即 NaN === NaN 返回false,NaN !== NaN 返回true。
因此,我们不能简单地通过 == 或者=== 运算符来判断数值是否非法数值,我们需要 isNaN() 或者 Number.isNaN() 两个函数进行判断。

typeof NaN   // "number"
NaN === NaN  // false
NaN !== NaN  // true

isNaN()
isNaN() 函数接收一个参数x,用来检查x是否非数字值。
isNaN() 函数接收参数x之后,会先把参数x转换为数字类型,任何非数字类型的值都会被强制转换为NaN,再做判断。
因此,isNaN() 函数的参数是NaN或者其他能够被转换为NaN的值时,结果都会返回true,其他值的情况下返回false。
故,isNaN() 函数会影响NaN的准确判断。

isNaN(null)   // false  Number(null) => 0
isNaN(undefined)   // true  Number(undefined) => NaN
isNaN(1)      // false
isNaN(' ')    // false  Number(' ') => 0
isNaN('1')    // false  Number('1') => 1
isNaN('abc')  // true   Number('abc') => NaN
isNaN('NaN')  // true   Number('NaN') => NaN
isNaN([])     // false  Number([]) => 0
isNaN([1])    // false  Number([1]) => 1
isNaN(['a'])  // true   Number(['a']) => NaN
isNaN({})	  // true   Number({}) => NaN
isNaN('2021/5/22')  // true  Number('2021/5/21') => NaN
isNaN(0 / 0)  // true
isNaN(NaN)    // true

Number.isNaN()
Number.isNaN() 函数也是接收一个参数x,判断x是否非数字值。
Number.isNaN() 函数在接收参数x之后,会首先判断参数x是否为数字类型,如果是数字类型则继续判断是否NaN。
因此,Number.isNaN() 相比全局函数 isNaN() 更为精准,只有在参数x本身为NaN的情况下才会返回true。

// 只有参数本身为NaN结果才为true
Number.isNaN(NaN)    // true
Number.isNaN(Number.NaN)   // true
Number.isNaN(0 / 0)  // true

// 以下在全局isNaN()函数的结果都为true,在Number.isNaN()结果都为false
isNaN(undefined)   // false
isNaN('abc')  // false
isNaN('NaN')  // false
isNaN(['a'])  // false
isNaN({})	  // false
isNaN('2021/5/22')  // false

// 以下仍然为false
isNaN(null)   // false
isNaN(1)      // false
isNaN(' ')    // false
isNaN('1')    // false
isNaN([])     // false
isNaN([1])    // false

11. == 操作符的强制类型转换规则?

在这里插入图片描述
对于 == 来说,如果对比双方的类型不一样,就会进行类型转换。假如对比 x 和 y 是否相同,就会进行如下判断流程:

  1. 首先会判断两者类型是否相同,相同的话就比较两者的大小;
  2. 类型不相同的话,就会进行类型转换;
  3. 会先判断是否在对比 null 和 undefined,是的话就会返回 true
  4. 判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number
1 == '1'1 ==  1
  1. 判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断
'1' == true'1' ==  11  ==  1
  1. 判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断
'1' == { name: 'js' }'1' == '[object Object]'  

12. 其他值到字符串的转换规则?

● Null 和 Undefined 类型 ,null 转换为 “null”,undefined 转换为 “undefined”,
● Boolean 类型,true 转换为 “true”,false 转换为 “false”。
● Number 类型的值直接转换,不过那些极小和极大的数字会使用指数形式。
● Symbol 类型的值直接转换,但是只允许显式强制类型转换,使用隐式强制类型转换会产生错误。
● 对普通对象来说,除非自行定义 toString() 方法,否则会调用 toString()(Object.prototype.toString())来返回内部属性 [[Class]] 的值,如"[object Object]"。如果对象有自己的 toString() 方法,字符串化时就会调用该方法并使用其返回值。

13. 其他值到数字值的转换规则?

● Undefined 类型的值转换为 NaN。
● Null 类型的值转换为 0。
● Boolean 类型的值,true 转换为 1,false 转换为 0。
● String 类型的值转换如同使用 Number() 函数进行转换,如果包含非数字值则转换为 NaN,空字符串为 0。
● Symbol 类型的值不能转换为数字,会报错。
● 对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。

为了将值转换为相应的基本类型值,抽象操作 ToPrimitive 会首先(通过内部操作 DefaultValue)检查该值是否有valueOf()方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用 toString() 的返回值(如果存在)来进行强制类型转换。

如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误。

14. 其他值到布尔类型的值的转换规则?

以下这些是假值:
• undefined
• null
• false
• +0、-0 和 NaN
• “”

假值的布尔强制类型转换结果为 false。从逻辑上说,假值列表以外的都应该是真值。

15. || 和 && 操作符的返回值?

|| 和 && 首先会对第一个操作数执行条件判断,如果其不是布尔值就先强制转换为布尔类型,然后再执行条件判断。

● 对于 || 来说,如果条件判断结果为 true 就返回第一个操作数的值,如果为 false 就返回第二个操作数的值。
● && 则相反,如果条件判断结果为 true 就返回第二个操作数的值,如果为 false 就返回第一个操作数的值。

|| 和 && 返回它们其中一个操作数的值,而非条件判断的结果

在js中&&运算符优先级大于||

a || b:

如果a是true,那么b不管是true还是false,都返回true。因此不用判断b了,这个时候刚好判断到a,因此返回a。
如果a是false,那么就要判断b,如果b是true,那么返回true,如果b是false,返回false,其实不就是返回b了吗。

a && b:

如果a是false,那么b不管是true还是false,都返回false,因此不用判断b了,这个时候刚好判断到a,因此返回a。
如果a是true,那么就要在判断b,和刚刚一样,不管b是true是false,都返回b。

      let a = true;
      let b = true;
      console.log(a && b);
      console.log(a || b);
 <script>
      console.log(false || 1); //1
      console.log(false || 0); //0
      console.log(true || 0); //true
      console.log(true || 1); true
      console.log(true == 1); //true
      console.log(true == 0); //false

      //   console.log(false && 1); //false
      //   console.log(false && 0); //false
      //   console.log(true && 0); //0
      //   console.log(true && 1); //1
      //   console.log(true == 1); //true
      //   console.log(true == 0); //false
    </script>

16. Object.is() 与比较操作符 “=”、“” 的区别?

● 使用双等号()进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。
● 使用三等号(
=)进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。
● 使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 是相等的。

      console.log(-0 === +0); //true
      console.log(NaN === NaN); //false

      console.log(Object.is(-0, +0)); //false
      console.log(Object.is(NaN, +NaN));//true

17. 什么是 JavaScript 中的包装类型?

在 JavaScript 中,基本类型是没有属性和方法的,但是为了便于操作基本类型的值,在调用基本类型的属性或方法时 JavaScript 会在后台隐式地将基本类型的值转换为对象,如:

const a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"

在访问’abc’.length时,JavaScript 将’abc’在后台转换成String(‘abc’),然后再访问其length属性。

JavaScript也可以使用Object函数显式地将基本类型转换为包装类型:

var a = 'abc'
Object(a) // String {"abc"}

也可以使用valueOf方法将包装类型倒转成基本类型:

var a = 'abc'
var b = Object(a)
var c = b.valueOf() // 'abc'

看看如下代码会打印出什么:

var a = new Boolean( false );
if (!a) {
	console.log( "Oops" ); // never runs
}

包装类返回的是一个对象

答案是什么都不会打印,因为虽然包裹的基本类型是false,但是false被包裹成包装类型后就成了对象,所以其非值为false,所以循环体中的内容不会运行。

18. JavaScript 中如何进行隐式类型转换?

首先要介绍ToPrimitive方法,这是 JavaScript 中每个值隐含的自带的方法,用来将值 (无论是基本类型值还是对象)转换为基本类型值。如果值为基本类型,则直接返回值本身;如果值为对象,其看起来大概是这样:

/**
* @obj 需要转换的对象
* @type 期望的结果类型
*/
ToPrimitive(obj,type)

type的值为number或者string。
(1)当type为number时规则如下:
● 调用obj的valueOf方法,如果为原始值,则返回,否则下一步;
● 调用obj的toString方法,后续同上;
● 抛出TypeError 异常。
(2)当type为string时规则如下:
● 调用obj的toString方法,如果为原始值,则返回,否则下一步;
● 调用obj的valueOf方法,后续同上;
● 抛出TypeError 异常。

可以看出两者的主要区别在于调用toString和valueOf的先后顺序。默认情况下:
● 如果对象为 Date 对象,则type默认为string;
● 其他情况下,type默认为number。
总结上面的规则,对于 Date 以外的对象,转换为基本类型的大概规则可以概括为一个函数:

var objToNumber = value => Number(value.valueOf().toString())
objToNumber([]) === 0
objToNumber({}) === NaN

而 JavaScript 中的隐式类型转换主要发生在+、-、*、/以及==、>、<这些运算符之间。而这些运算符只能操作基本类型值,所以在进行这些运算前的第一步就是将两边的值用ToPrimitive转换成基本类型,再进行操作。

以下是基本类型的值在不同操作符的情况下隐式转换的规则 (对于对象,其会被ToPrimitive转换成基本类型,所以最终还是要应用基本类型转换规则):

  1. +操作符+操作符的两边有至少一个string类型变量时,两边的变量都会被隐式转换为字符串;其他情况下两边的变量都会被转换为数字。
1 + '23' // '123'
 1 + false // 1 
 1 + Symbol() // Uncaught TypeError: Cannot convert a Symbol value to a number
 '1' + false // '1false'
 false + true // 1
  1. -、*、\操作符NaN也是一个数字
1 * '23' // 23
 1 * false // 0
 1 / 'aa' // NaN
  1. 对于==操作符
    操作符两边的值都尽量转成number:
3 == true // false, 3 转为number为3,true转为number为1
'0' == false //true, '0'转为number为0,false转为number为0
'0' == 0 // '0'转为number为0
  1. 对于<和>比较符
'ca' < 'bd' // false
'a' < 'b' // true

其他情况下,转换为数字再比较:

'12' < 13 // true
false > -1 // true

以上说的是基本类型的隐式转换,而对象会被ToPrimitive转换为基本类型再进行转换:

var a = {}
a > 2 // false

其对比过程如下:

a.valueOf() // {}, 上面提到过,ToPrimitive默认type为number,所以先valueOf,结果还是个对象,下一步
a.toString() // "[object Object]",现在是一个字符串了
Number(a.toString()) // NaN,根据上面 < 和 > 操作符的规则,要转换成数字
NaN > 2 //false,得出比较结果

又比如:

var a = {name:'Jack'}
var b = {age: 18}
a + b // "[object Object][object Object]"

运算过程如下:

a.valueOf() // {},上面提到过,ToPrimitive默认type为number,所以先valueOf,结果还是个对象,下一步
a.toString() // "[object Object]"
b.valueOf() // 同理
b.toString() // "[object Object]"
a + b // "[object Object][object Object]"

19. + 操作符什么时候用于字符串的拼接?

根据 ES5 规范,如果某个操作数是字符串或者能够通过以下步骤转换为字符串的话,+ 将进行拼接操作。如果其中一个操作数是对象(包括数组),则首先对其调用 ToPrimitive 抽象操作,该抽象操作再调用 [[DefaultValue]],以数字作为上下文。如果不能转换为字符串,则会将其转换为数字类型来进行计算。

简单来说就是,如果 + 的其中一个操作数是字符串(或者通过以上步骤最终得到字符串),则执行字符串拼接,否则执行数字加法。

那么对于除了加法的运算符来说,只要其中一方是数字,那么另一方就会被转为数字。

20. 为什么会有BigInt的提案?

JavaScript中Number.MAX_SAFE_INTEGER表示最⼤安全数字,计算结果是9007199254740991,即在这个数范围内不会出现精度丢失(⼩数除外)。但是⼀旦超过这个范围,js就会出现计算不准确的情况,这在⼤数计算的时候不得不依靠⼀些第三⽅库进⾏解决,因此官⽅提出了BigInt来解决此问题。

21. object.assign和扩展运算法是深拷贝还是浅拷贝,两者区别

扩展运算符:

let outObj = {
  inObj: {a: 1, b: 2}
}
let newObj = {...outObj}
newObj.inObj.a = 2
console.log(outObj) // {inObj: {a: 2, b: 2}}

Object.assign():

let outObj = {
  inObj: {a: 1, b: 2}
}
let newObj = Object.assign({}, outObj)
newObj.inObj.a = 2
console.log(outObj) // {inObj: {a: 2, b: 2}}

可以看到,两者都是浅拷贝。
● Object.assign()方法接收的第一个参数作为目标对象,后面的所有参数作为源对象。然后把所有的源对象合并到目标对象中。它会修改了一个对象,因此会触发 ES6 setter。
● 扩展操作符(…)使用它时,数组或对象中的每一个值都会被拷贝到一个新的数组或对象中。它不复制继承的属性或类的属性,但是它会复制ES6的 symbols 属性。

22. 如何判断一个对象是空对象

使用JSON自带的.stringify方法来判断:

if(Json.stringify(Obj) == '{}' ){
    console.log('空对象');
}

使用ES6新增的方法Object.keys()来判断:

if(Object.keys(Obj).length < 0){
    console.log('空对象');
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值