1.JavaScript规定了几种语言类型

  • Number

  • String
  • Boolean
    • true/false
  • Null
    • null 表示的是:“定义了但是为空”。所以,在实际编程时,我们一般不会把变量赋值为 undefined,这样可以保证所有值为 undefined 的变量,都是从未赋值的自然状态。
    • Null 类型也只有一个值,就是 null,它的语义表示空值,与 undefined 不同,null 是 JavaScript 关键字,所以在任何代码中,你都可以放心用 null 关键字来获取 null 值。
  • Undefined
    • 函数默认返回值

function ret() { // 默认是返回 undefined }

  • 获取对象不存在的 key

var obj = {} obj.name

  • 获取数组不存在的下标

var aa = [] aa[0] undefined

  • 声明变量,不初始化值

var foo;

  • Object
  • BigInt
  • Symbol
    • 其中什么是symbol?

Symbol函数会生成一个唯一的值
可以理解为Symbol类型跟字符串是接近的
但每次生成唯一的值,也就是每次都不相等,
至于它等于多少,并不重要 这对于一些字典变量,比较有用。
Symbol 是 ES6 中引入的新类型,它是一切非字符串的对象 key 的集合,在 ES6 规范中,整个对象系统被用 Symbol 重塑。
Symbol 可以具有字符串类型的描述,但是即使描述相同,Symbol 也不相等。
创建 Symbol 的方式是使用全局的 Symbol 函数。例如:
var mySymbol = Symbol(“my symbol”);

任意创建两个Symbol都不会相同

  1. obj['name'] = 'tianyufei';
  2. obj.name = 'xxx'; //修改了
  3. console.log(obj['name']); //xxx
  4. var xxx = "na" + "me";
  5. console.log(obj[xxx]);//本想输出name但输出xxx
  6. 【注】问题是,如果用字符串作为对象属性,会导致,只要值是对象的这个属性,就可以访问。
  7. // 避免以上问题,将属性设置为Symbol类型
  8. let name = Symbol("描述1:我是name属性");
  9. var xxx = Symbol();
  10. console.log(name === xxx); //false任意两个Symbol都不会相同
  11. obj[name] = 'tianyufei';
  12. console.log(obj[name]); //tianyufei
  13. console.log(obj); //{Symbol(描述1:我是name属性): "tianyufei"}

2.JS对象的底层数据结构是什么

详细讲解:
https://www.jianshu.com/p/7d3ab9a22b11?mode=dark
JavaScript使用的是 堆(Heap) 和 栈( Stack)
JavaScript基本类型数据都是直接按值存储在栈中的(Undefined、Null、不是new出来的布尔、数字和字符串),每种类型的数据占用的内存空间的大小是确定的,并由系统自动分配和自动释放。这样带来的好处就是,内存可以及时得到回收,相对于堆来说 ,更加容易管理内存空间。

JavaScript引用类型数据被存储于堆中 (如对象、数组、函数等,它们是通过拷贝和new出来的)。其实,说存储于堆中,也不太准确,因为,引用类型的数据的地址指针是存储于栈中的,当我们想要访问引用类型的值的时候,需要先从栈中获得对象的地址指针,然后,在通过地址指针找到堆中的所需要的数据。

3.Symbol类型在实际开发中的应用、可手动实现一个简单的Symbol

开发中的应用:https://blog.csdn.net/qq_41070239/article/details/90053964
简单的Symbol :https://segmentfault.com/a/1190000015262174

4.JS中的变量在内存中的具体存储形式

js变量类型:分为基本类型和引用

  • 基本类型是保存在栈内存中的简单数据段,它们的值都有固定的大小,保存在栈空间,通过按值访问,(有undefined,null,以及不是new出来的布尔、字符串、数字)
  • 引用类型是保存在堆内存中的对象,值大小不固定,栈内存中存放的该对象的访问地址指向堆内存中的对象,JavaScript不允许直接访问堆内存中的位置,因此操作对象时,实际操作对象的引用。

(有对象、数组/函数/拷贝或new出的变量)

5.基本类型对应的内置对象,以及他们之间的装箱拆箱操作

typeof 和 instanceof 区别

  • typeof: 经常用来检测一个变量是不是最基本的数据类型
  • instanceof: 用来判断某个构造函数的 prototype 属性所指向的对象是否存在于另外一个要检测对象的原型链上。简单说就是判断一个引用类型的变量具体是不是某种类型的对象

拆箱和装箱操作
引用类型有个特殊的基本包装类型,它包括String、Number和Boolean。
作为字符串的a可以调用方法(进行了装箱操作)

  1. 装箱:把基本数据类型转化为对应的引用数据类型的操作

装箱分为:隐式装箱和显式装箱

  1. 1. 隐式装箱: (每当读取一个基本类型的时候,后台就会创建一个对应的基本包装类型对象,从而让我们能够调用一些方法来操作这些数据。(隐式装箱))
  1. let a = 'zhang';
  2. let b = a.indexOf('h') // 1
  3. // 后台运行的顺序
  4. let a = new String('zhang')
  5. let b = a.indexOf('h')
  6. a = null
  7. a是基本类型,不是对象,不应该具有方法,js内部进行了一些列处理(装箱), 使得它能够调用方法。在这个基本类型上调用方法,其实是在这个基本类型对象上调用方法。这个基本类型的对象是临时的,它只存在于方法调用那一行代码执行的瞬间,执行方法后立刻被销毁。
  8. 实现机制:
  9. 创建String类型的一个实例;
  10. 在实例上调用指定的方法;
  11. 销毁这个实例;
  1. 2. 显式装箱:通过内置对象可以对BooleanObjectString等可以对基本类型显示装箱
  1. let a = 'zhang'
  1. 拆箱: 拆箱和装箱相反,就是把引用类型转化为基本类型的数据,通常通过引用类型的valueof()和toString()方法实现
    1. let name = new String ('zhang')
    2. let age = new Number (22)
    3. console.log(typeof name) // object
    4. console.log(typeof age) // object
    5. 引用类型是object
    6. 下面进行拆箱操作 ---- 把引用类型转成基本类型
    7. console.log(typeof name.toString()) // string 基本类型
    8. console.log(typeof age.toString()) // string
    9. console.log(typeof age.valueof()) // number

    6.理解值类型和引用类型

    同4

    7.null和undefined的区别

  • 定义不同:null是空值,表示一个变量不再指向任何对象地址;undefined是没有定义,(表示应该有一个值,但没有定义)
  • 类型不同

    null的类型是object,undefined的类型是undefined。null代表没有对象,是空值,undefined是缺少值。

    • 解释下typeof null 为 ‘object’的bug

JavaScript中的数据在底层是以二进制存储,比如null所有存储值都是0,但是底层的判断机制,只要前三位为0,就会判定为object,所以才会有typeof null === ‘object’这个bug。

  • 用法不同:
    • null

(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。

  1. Object.getPrototypeOf(Object.prototype)
  2. // null
  • undefined

(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。

8.至少可以说出三种判断JavaScript数据类型的方式,以及他们的优缺点,如何准确的判断数组类型

原文地址:https://www.cnblogs.com/onepixel/p/5126046.html

  • typeof

(右侧是一元表达式,返回这个表达式的数据类型,返回结果包括number boolean string object undefined function)

  • 优缺点:可以对基础数据类型做出 准确的判断,在对于引用类型的返回的基本都是object(除了function外)。判断是引用类型,typeof使用不方便
    • instanceof (判断A是否为B的实例)

表达式为:A instanceof B,如果 A是B的实例,则返回true; 否则返回false
在这里特别注意的是 instanceof检测的是原型
特殊问题:

  1. [] instanceof Array; // true
  2. [] instanceof Object; // true
  3. 【】能被判断出Array也能判断出object,因为一切皆是对象
  4. {} instanceof Object;// true
  5. new Date() instanceof Date;// true
  6. function Person(){};
  7. new Person() instanceof Person;
  8. new Date() instanceof Object;// true
  9. new Person instanceof Object;// true

[ ]、Array、Object 三者之间的关系
从 instanceof 能够判断出 [ ].proto 指向 Array.prototype,而 Array.prototype.proto 又指向了Object.prototype,最终 Object.prototype.proto 指向了null,标志着原型链的结束。因此,[]、Array、Object 就在内部形成了一条原型链:
截屏2021-12-06 下午7.51.50.png
instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。
针对数组的这个问题,ES5 提供了 Array.isArray() 方法 。该方法用以确认某个对象本身是否为 Array 类型,而不区分该对象在哪个环境中创建。
Array.isArray() 本质上检测的是对象的 [[Class]] 值,[[Class]] 是对象的一个内部属性,里面包含了对象的类型信息,其格式为 [object Xxx] ,Xxx 就是对应的具体类型 。对于数组而言,[[Class]] 的值就是 [object Array] 。

  • constructor 查看对象对应的构造函数

当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用 (构造函数名.prototype.constructor = 构造函数名)
1. null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。
2. 函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object

  • toString 是Object的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。

对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
截屏2021-12-06 下午7.59.55.png
判断数组类型方法:
最好用Array.isAarray(value),也可以用instanceof 和 object.prototype.toString.call

9.可能发生隐式类型转换的场景以及转换原则,应如何避免或巧妙应用

原文链接: https://www.nblogs.com/archives/496/

10.出现小数精度丢失的原因,JavaScript可以存储的最大数字、最大安全数字,JavaScript处理大数字的方法、避免精度丢失的方法

  • 出现小数精度丢失的原因

原因其实就是js number类型运算都需要先将十进制转二进制
但小数点后的位数转二进制会出现无限循环的问题,只能舍0入1,所以会出现小数点丢失问题
查看详细原因(链接)

  • JavaScript可以存储的最大数字、最大安全数字

最大安全数是 2^53-1
最大整数范围: -2^53-1 ~ 2^53-1
浮点类型:1位符号位, 11个指数位,52个尾数位(小数位)

可以通过 Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER 来获取js的最大安全数和最小安 全数;得到的值就是Math.pow(2, 53)-1,所以在js中只要计算结果小于Math.pow(2, 53)就不会丢失精度。
截屏2021-11-17 下午7.44.45.png

  • JavaScript处理大数字的方法、避免精度丢失的方法

1.小数精度问题
将小数转化为整数进行运算

  1. function formatFloat (num1, num2) {
  2. var baseNum, baseNum1, baseNum2;
  3. try {
  4. baseNum1 = num1.toString().split(".")[1].length;
  5. } catch (e) {
  6. baseNum1 = 0;
  7. }
  8. try {
  9. baseNum2 = num2.toString().split(".")[1].length;
  10. } catch (e) {
  11. baseNum2 = 0;
  12. }
  13. baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
  14. return (num1 * baseNum + num2 * baseNum) / baseNum;
  15. };
  16. console.log(formatFloat(0.1,0.2))
  1. 限制精度,只保留小数部分位数,减小精度出现的误差问题
  1. Number.toFixed()
  2. console.log((0.1 + 0.2).toFixed(12) == 0.3)
  3. > true
  4. console.log((0.1 + 0.2).toFixed(12))
  5. > 0.300000000000
  6. console.log((2.4/0.8).toFixed(12))
  7. > 3.000000000000

2.解决大整数精度问题

  1. 算法:
  2. function bigNumberAdd(a,b) {
  3. var res = '', c = 0;//进位值,初始c值为0
  4. a = a.split('');//将数据拆分为数组
  5. b = b.split('');//同上
  6. while (a.length || b.length || c) {//遍历数据
  7. c += ~~a.pop() + ~~b.pop();//进位值c
  8. res = c % 10 + res;//依次相加
  9. c = c > 9;//若c大于9,c为true,下次循环中true转换为1,即有进位
  10. }
  11. return res.replace(/^0+/, '');//返回值
  12. }
  13. 以上方法即可正确的实现大数据相加
  14. bigNumberAdd('12478945645654','489789411231231523');//调用
  15. 注意:参数需传递字符串类型