前端面试知识点总结JavaScript基础之变量和类型(一)

目录

一、JavaScript基础

变量和类型

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

2、JavaScript对象的底层数据结构是什么

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

4、JavaScript中的变量在内存中的具体存储形式

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

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

7、null和undefined的区别

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

9、可能发生隐式类型转换的场景以及转换原则

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


一、JavaScript基础

变量和类型

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

     两种类型:基本类型和引用类型

  • 6种基本类型:String、Number、Boolean、Null、Undefind、Symbol
  • 1种引用类型:Object

2、JavaScript对象的底层数据结构是什么

     JavaScript中的数据在底层是以二进制存储的。

       比如null所有存储值都是0,但是底层的判断机制,只要前三位为0,就会判定为object,所以才会有typeof null === 'object'这个bug;

       同理可以解释数字类型中的另外一个bug,即:0.1+0.2 != 0.3;

       因为浮点数在运算时,会先将数字转成二进制数,然后进行二进制运算,在转换过程中,会出现取余不尽的情况,即有无限小数,然后会进行类似四舍五入的方式进行保留,导致运算精度不准确,当然,解决这个问题,可以让他们同时乘以一个极大的数,然后除以极大的数来抵消掉,项目中,也可以用big.js来帮助处理;

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

  •  场景一:使用Symbol来作为对象属性名key

      特性:Symbol类型的key是不能通过Object.keys()或者for...in来枚举的,它未被包含在对象自身的属性名集合(property names)之中。所以,利用该特性,我们可以把一些不需要对外操作和访问的属性使用Symbol来定义。也正因为这样一个特性,当使用JSON.stringify()将对象转换成JSON字符串的时候,Symbol属性也会被排除在输出内容之外。

let obj = {
   [Symbol('name')]: 'zzz',
   age: 18,
   title: 'Engineer'
}
Object.keys(obj)   // ['age', 'title']
for (let p in obj) {
   console.log(p)   // 分别会输出:'age' 和 'title'
}
Object.getOwnPropertyNames(obj)   // ['age', 'title']
JSON.stringify(obj)  // {"age":18,"title":"Engineer"}
  •  场景二:使用Symbol代替常量
/*
const TYPE_AUDIO = 'AUDIO'
const TYPE_VIDEO = 'VIDEO'
const TYPE_IMAGE = 'IMAGE'
*/
const TYPE_AUDIO = Symbol()
const TYPE_VIDEO = Symbol()
const TYPE_IMAGE = Symbol()//保证变量的唯一性,但是这种场景意义不是很大,少了一些特定变量名称的粘贴复制吧,const声明的就是唯一值了
function handleFileResource(resource) {
  switch(resource.type) {
    case TYPE_AUDIO:
      playAudio(resource)
      break
    case TYPE_VIDEO:
      playVideo(resource)
      break
    case TYPE_IMAGE:
      previewImage(resource)
      break
    default:
      throw new Error('Unknown type of resource')
  }
}
  •  场景三:使用Symbol定义类的私有属性/方法

        在JavaScript中,是没有如Java等面向对象语言的访问控制关键字private的,类上所有定义的属性或方法都是可公开访问的。因此这对我们进行API的设计时造成了一些困扰。
而有了Symbol以及模块化机制,类的私有属性和方法才变成可能。

  • 场景四:注册和获取全局Symbol

       通常情况下,我们在一个浏览器窗口中(window),使用Symbol()函数来定义和Symbol实例就足够了。但是,如果你的应用涉及到多个window(最典型的就是页面中使用了<iframe>),并需要这些window中使用的某些Symbol是同一个,那就不能使用Symbol()函数了,因为用它在不同window中创建的Symbol实例总是唯一的,而我们需要的是在所有这些window环境下保持一个共享的Symbol。这种情况下,我们就需要使用另一个API来创建或获取Symbol,那就是Symbol.for(),它可以注册或获取一个window间全局的Symbol实例。

let gs1 = Symbol.for('global_symbol_1')  //注册一个全局Symbol
let gs2 = Symbol.for('global_symbol_1')  //获取全局Symbol
gs1 === gs2  // true

4、JavaScript中的变量在内存中的具体存储形式

  • 基本数据类型,内容存储在栈内存当中,它们的值都有固定的大小,通过值进行访问。
  • 引用数据类型,内容存储在堆内存当中,值大小不固定,通过引用进行访问,其中引用及变量标识存储在栈当中。

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

  • 基本类型的内置对象有String()Number()Boolean()Symbol()
  • 引用类型的内置对象有RegExp()Date()Array()Object()Function()Error()

      装箱:将基本数据类型转为引用数据类型。装箱分为隐式和显示

  • 隐式装箱: 每当读取一个基本类型的值时,后台会创建一个该基本类型所对应的对象。在这个基本类型上调用方法,其实是在这个基本类型对象上调用方法。这个基本类型的对象是临时的,它只存在于方法调用那一行代码执行的瞬间,执行方法后立刻被销毁。

let num=123;
num.toFixed(2); // '123.00'
//上方代码在后台的真正步骤为
var c = new Number(123);
c.toFixed(2);
c = null;

       (1)创建一个 Number 类型的实例。

       (2)在实例上调用方法。

       (3)销毁实例。

  • 显式装箱: 通过内置对象 Boolean、Object、String 等可以对基本类型进行显示装箱。

var obj = new String('123');

       拆箱:拆箱与装箱相反,将引用数据类型转为基本数据类型。拆箱过程内部调用了抽象操作 ToPrimitive 。该操作接受两个参数,第一个参数是要转变的对象,第二个参数 PreferredType 是对象被期待转成的类型。第二个参数不是必须的,默认该参数为 number,即对象被期待转为数字类型。

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

  • 类型就是基本数据类型(如int,double 等)

       1、占用空间固定,保存在栈中
       2、保存与复制的是值本身
       3、使用typeof检测数据的类型
       4、基本类型数据是值类型

  • 引用类型,是指除了基本的变量类型之外的所有类型(如通过 class 定义的类型)

       1、占用空间不固定,保存在堆中
       2、保存与复制的是指向对象的一个指针
       3、使用instanceof检测数据类型
       4、使用new()方法构造出的对象是引用型

7、nullundefined的区别

  • null——表示一个变量将来可能指向一个对象。一般用于主动释放指向对象的引用。
  • undefined——表示变量声明过但并未赋过值。它是所有未赋值变量的默认值。

      在 JavaScript 中, null 用于对象, undefined 用于变量,属性和方法。对象只有被定义才有可能为 null,否则为 undefined。null 和 undefined 的值相等,但类型不等。所以设置一个值为null是合理的,但是设置一个值为undefined就不合理。

null == undefined //  true
null === undefined // false
!!null // false
!!undefined // false
Number(null) //0
Number(undefined) //NaN
typeof null // object
typeof undefined // undefined

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

  • 第一种:typeof
  1. typeof返回一个表示数据类型的字符串,返回结果包括: number boolean string object undefined function等。
  2. typeof可以对js基础数据类型做出准确的判断,在对于引用类型返回的基本上都是object。判断是引用类型,typeof使用起来比较不方便。

     注意:typeof null也是返回object

  • 第二种:instanceof

       instanceof是用来判断A是否为B的实例时,表达式为:A instanceof B,如果 A是B的实例,则返回true; 否则返回false。在这里特别注意的是 instanceof检测的是原型。

  • 第三种:Object.prototype.toString

       toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString运行时this指向的对象类型, 返回的类型格式为[object,xxx],xxx是具体的数据类型,基本上所有对象的类型都可以通过这个方法获取到。但是IE6下,undefined和null均为Object。

  • 第四种:constructor

       constructor是查看对象对应的构造函数,constructor在对应对象的原型下面,是自动生成的,当我们写一个构造函数的时候,程序自动添加:构造函数名.prototype.constructor = 构造函数名。

9、可能发生隐式类型转换的场景以及转换原则

  • js数据类型隐式转换主要分为三种情况:
  1. 转换为string
  2. 转换为number
  3. 转换为boolean
  • 转换原则:隐式类型转换,Javascript默认自动转换,没有任何警告。

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

        计算机中的计算使用的是二进制,二进制只有0和1,遵照十进制四舍五入,二进制是0舍1入,这是浮点数计算精度丢失的根本原因。

        大整数的精度丢失跟浮点数本质一样,尾数位最大是52位,因此JS中能精准表示的最大整数是Math.pow(2, 53),大于该值可能会丢失精度。

  • 解决方法:
//加法
Number.prototype.add = function(arg) {
  var r1, r2, m;
  try {
    r1 = this.toString().split(".")[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  m = Math.pow(10, Math.max(r1, r2));
  return (this * m + arg * m) / m;
};
//减法
Number.prototype.sub = function(arg) {
  return this.add(-arg);
};

//乘法
Number.prototype.mul = function(arg) {
  var m = 0,
    s1 = this.toString(),
    s2 = arg.toString();
  try {
    m += s1.split(".")[1].length;
  } catch (e) {}
  try {
    m += s2.split(".")[1].length;
  } catch (e) {}
  return (
    (Number(s1.replace(".", "")) * Number(s2.replace(".", ""))) /
    Math.pow(10, m)
  );
};

//除法
Number.prototype.div = function(arg) {
  var t1 = 0,
    t2 = 0,
    r1,
    r2;
  try {
    t1 = this.toString().split(".")[1].length;
  } catch (e) {}
  try {
    t2 = arg.toString().split(".")[1].length;
  } catch (e) {}
  with (Math) {
    r1 = Number(this.toString().replace(".", ""));
    r2 = Number(arg.toString().replace(".", ""));
    return (r1 / r2) * pow(10, t2 - t1);
  }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值