前端秘籍之=>八股文经卷=>(原生Js篇)【持续更新中...】

目录

  • JavaScript部分
    • 1.JavaScript 有哪些数据类型,它们的区别?
    • 2.数据类型检测的方式有哪些?
    • 3.Null 和 undefined 有什么区别?
    • 4.如何获取安全的 undefined 值?
    • 5.Object.is() 与比较操作符 “===” 和“ == ”的区别?
    • 6. 谈谈什么是 JavaScript 中的包装类型?
    • 7.为什么会有 BigInt类型 的提案?
    • 8.如何判断一个对象是空对象?
    • 9.const 声明的值能否被修改?
    • 10.是否可以new 一个箭头函数?如果 new 一个箭头函数的会怎么样?
    • 11.箭头函数的 this 指向哪⾥?
    • 12.说说扩展运算符 “...” 的作用及使用场景
    • 13.谈谈对 JSON 的理解
    • 14.JavaScript 脚本延迟加载的方式有哪些?
    • 15.说说什么是 DOM 和 BOM?
    • 16.聊聊 什么是函数尾调用,使用尾调用有什么好处?

JavaScript部分

前端秘籍之=>八股文经卷=>(原生Js篇)【持续更新中...】_第1张图片

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

答:

共有 8种数据类型 ,分别是:1:Undefined,2:Null,3:Object,4:Boolean,5:Number,6: String,7:Symbol ,8:BigInt。
其中 Symbol 和 BigInt 是 ES6 中新增的数据类型;

●Symbol 代表创建后独一无二且不可变的数据类型,它主要是为了 解决可能出现的全局变量冲突的问题。
●BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数, 使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。
这些数据可以分为基本数据类型和引用数据类型:
●栈:基本数据类型(Undefined、Null、Boolean、Number、String);
●堆:引用数据类型(对象、数组和函数) 两种类型的区别在于存储位置的不同;
两种类型的区别在于存储位置的不同:
●原始数据类型直接存储在栈(stack)中的简单数据段,占据空间 小、大小固定,属于被频繁使用数据,所以放入栈中存储;
●引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固 定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈 中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引 用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。 堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:
●在数据结构中,栈中数据的存取方式为先进后出。
●堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大 小来规定。
在操作系统中,内存被分为栈区和堆区:
●栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的 值等。其操作方式类似于数据结构中的栈。
●堆区内存一般由开发着分配释放,若开发者不释放,程序结束时可 能由垃圾回收机制回收。

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

答:(1):typeof

前端秘籍之=>八股文经卷=>(原生Js篇)【持续更新中...】_第2张图片

其中数组、对象、null 都会被判断为 object,其他判断都正确。常用来判断基本数据类型,其中 判断Null,为Object ,是js历史遗留问题。

答:(2)instanceof

前端秘籍之=>八股文经卷=>(原生Js篇)【持续更新中...】_第3张图片
instanceof 可以正确判断对象的类型,其内部运行机制是判断在其 原型链中能否找到该类型的原型。
可以看到,instanceof 只能正确判断引用数据类型,而不能判断基 本数据类型。instanceof 运算符可以用来测试一个对象在其原型链 中是否存在一个构造函数的 prototype 属性。

答:(3)constructor

前端秘籍之=>八股文经卷=>(原生Js篇)【持续更新中...】_第4张图片
constructor 有两个作用,一是判断数据的类型,二是对象实例通过 constrcutor 对象访问它的构造函数。需要注意,如果创建一个对象 来改变它的原型,constructor 就不能用来判断数据类型了:如下:
前端秘籍之=>八股文经卷=>(原生Js篇)【持续更新中...】_第5张图片

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

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

3.Null 和 undefined 有什么区别?

答:

首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型 分别都只有一个值,就是 undefined 和 null。 undefined 代表的含义是未定义,null 代表的含义是空对象。一般 变量声明了但还没有定义的时候会返回 undefined,
null 主要用于 赋值给一些可能会返回对象的变量,作为初始化。
undefined 在 JavaScript 中不是一个保留字,这意味着可以使用 undefined 来作为一个变量名,但是这样的做法是非常危险的,它会 影响对 undefined 值的判断。我们可以通过一些方法获得安全的 undefined 值,比如说 void 0。
当对这两种类型使用 typeof 进行判断时,Null 类型化会返回 “object”,这是一个历史遗留的问题。当使用双等号对两种类型的 值进行比较时会返回 true,使用三个等号时会返回 false。

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

答:

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

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

答:

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

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

答:

在 JavaScript 中,基本类型是没有属性和方法的,但是为了便于操 作基本类型的值,在调用基本类型的属性或方法时 JavaScript 会在 后台隐式地将基本类型的值转换为对象,如:
在这里插入图片描述
在 访 问 ‘abcdef’.length 时 , JavaScript 将 ‘abc’ 在 后 台 转 换 成 String(‘abcdef’),然后再访问其 length 属性。
JavaScript 也可以使用 Object 函数显式地将基本类型转换为包装类 型:
在这里插入图片描述
也可以使用 valueOf 方法将包装类型倒转成基本类型:
在这里插入图片描述

7.为什么会有 BigInt类型 的提案?

答:

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

8.如何判断一个对象是空对象?

答:

        let obj = {};
        if (JSON.stringify(obj) == "{}") {   //JSON方法
            console.log("obj是空对象");
        }
        if (Object.keys(obj).length < 1) {  //Object 方法
            console.log("obj是空对象");
        }

9.const 声明的值能否被修改?

答:

const 保证的并不是变量的值不能改动,而是变量指向的那个内存地 址不能改动。对于基本类型的数据(数值、字符串、布尔值),其值 就保存在变量指向的那个内存地址,因此等同于常量。 但对于引用类型的数据(主要是对象和数组)来说,变量指向数据的 内存地址,保存的只是一个指针,const 只能保证这个指针是固定不 变的,至于它指向的数据结构是不是可变的,就完全不能控制了。

10.是否可以new 一个箭头函数?如果 new 一个箭头函数的会怎么样?

答:

不可以。
箭头函数是ES6中的提出来的,它没有prototype,也没有自己的this 指向,更不可以使用 arguments 参数,所以不能 New 一个箭头函数。
new 操作符的实现步骤如下:
1.创建一个对象 。
2.将构造函数的作用域赋给新对象(也就是将对象的__proto__属性 指向构造函数的 prototype 属性)。
3.指向构造函数中的代码,构造函数中的 this 指向该对象(也就是 为这个对象添加属性和方法)
4.返回新的对象 。
所以,上面的第二、三步,箭头函数都是没有办法执行的。

11.箭头函数的 this 指向哪⾥?

答:

箭头函数不同于传统 JavaScript 中的函数,箭头函数并没有属于⾃ ⼰的 this,它所谓的 this 是捕获其所在上下⽂的 this 值,作为⾃ ⼰的 this 值,并且由于没有属于⾃⼰的 this,所以是不会被 new 调⽤的,这个所谓的 this 也不会被改变。

12.说说扩展运算符 “…” 的作用及使用场景

答:

扩展运算符使用场景分为: 对象扩展运算符 和 数组扩展运算符;
(1)对象扩展运算符
对象的扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷
贝到当前对象之中。
在这里插入图片描述
上述方法,等同于原生:
在这里插入图片描述
Object.assign 方法用于对象的合并,将源对象(source)的所有可
枚举属性,复制到目标对象(target)。Object.assign 方法的第一
个参数是目标对象,后面的参数都是源对象。(如果目标对象与源对
象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面
的属性)。
同样,如果用户自定义的属性,放在扩展运算符后面,则扩展运算符
内部的同名属性会被覆盖掉。如下:在这里插入图片描述
利用上述特性就可以很方便的修改对象的部分属性。这也是为什么在 redux 中的
reducer 函数规定必须是一个纯函数,reducer 中的 state 对象要求
不能直接修改,可以通过扩展运算符把修改路径的对象都复制一遍,
然后产生一个新的对象返回。
不过这里需要注意的是:扩展运算符对对象实例的拷贝属于浅拷贝。了解深浅拷贝
(2)数组扩展运算符
数组的扩展运算符可以将一个数组转为用逗号分隔的参数序列,且每
次只能展开一层数组。
在这里插入图片描述
数组中常应用:

     //将数组转换为参数序列,为函数传参
      let arr = [1, 2];
      function fn(x, y) {
        return x + y;
      }
      let data = fn(...arr);
      console.log(data);   //3
     //同样也能复制数组
     let arr = [1, 2];
     let str= [...arr];  //[1, 2]

要记住:扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷
贝到当前对象之中,这里参数对象是个数组,数组里面的所有对象都
是基础数据类型,将所有基础数据类型重新拷贝到新的数组中。
合并数组:
在这里插入图片描述
扩展运算符与解构赋值结合起来,用于生成数组
前端秘籍之=>八股文经卷=>(原生Js篇)【持续更新中...】_第6张图片
需要注意:如果将扩展运算符用于数组赋值,只能放在参数的最后一
位,否则会报错。
字符串数组转成真实数组
在这里插入图片描述
任何 Iterator 接口的对象,都可以用扩展运算符转为真正的数组;
还可以在使用 Math 函数获取数组中特定的值
在这里插入图片描述

13.谈谈对 JSON 的理解

答:

JSON 是一种基于文本的轻量级的数据交换格式。它可以被任何的编程语言读取和作为数据格式来传递。在项目开发中,使用 JSON 作为前后端数据交换的方式。在前端通过将一个符合 JSON 格式的数据结构序列化为JSON 字符串,然后将它传递到后端,后端通过 JSON 格式的字符串解析后生成对应的数据结构,以此来实现前后端数据的一个传递。
因为 JSON 的语法是基于 js 的,因此很容易将 JSON 和 js 中的对象弄混,但是应该注意的是 JSON 和 js 中的对象不是一回事,JSON中对象格式更加严格,比如说在 JSON 中属性值不能为函数,不能出现 NaN 这样的属性值等,因此大多数的 js 对象是不符合 JSON 对象的格式的。
在 js 中提供了两个函数来实现 js 数据结构和 JSON 格式的转换处理,JSON.stringify 函数,通过传入一个符合 JSON 格式的数据结构,将其转换为一个 JSON 字符串。如果传入的数据结构不符合 JSON 格式,那么在序列化的时候会对这些值进行对应的特殊处理,使其符合规范。在前端向后端发送数据时,可以调用这个函数将数据对象转化
为 JSON 格式的字符串。
JSON.parse() 函数,这个函数用来将 JSON 格式的字符串转换为一个 js 数据结构,如果传入的字符串不是标准的 JSON 格式的字符串的话,将会抛出错误。当从后端接收到 JSON 格式的字符串时,可以通过这个方法来将其解析为一个 js 数据结构,以此来进行数据的访问。

14.JavaScript 脚本延迟加载的方式有哪些?

答:

延迟加载就是等页面加载完成之后再加载 JavaScript 文件。js 延 迟加载有助于提高页面加载速度。
defer 属性:给 js 脚本添加 defer 属性,这个属性会让脚本的加 载与文档的解析同步解析,然后在文档解析完成后再执行这个脚本文 件,这样的话就能使页面的渲染不被阻塞。多个设置了 defer 属性的脚本按规范来说最后是顺序执行的,但是在一些浏览器中可能不是 这样。
async 属性:给 js 脚本添加 async 属性,这个属性会使脚本异步 加载,不会阻塞页面的解析过程,但是当脚本加载完成后立即执行 js 脚本,这个时候如果文档没有解析完成的话同样会阻塞。多个 async 属性的脚本的执行顺序是不可预测的,一般不会按照代码的顺序依次 执行。
动态创建 DOM 方式:动态创建 DOM 标签的方式,可以对文档的加载 事件进行监听,当文档加载完成后再动态的创建 script 标签来引入 js 脚本。
使用 setTimeout 延迟方法:设置一个定时器来延迟加载 js 脚本文 件让 JS 最后加载:将 js 脚本放在文档的底部,来使 js 脚本尽可能 的在最后来加载执行。

15.说说什么是 DOM 和 BOM?

答:

DOM 指的是文档对象模型,它指的是把文档当做一个对象,这个对象 主要定义了处理网页内容的方法和接口。
BOM 指的是浏览器对象模型,它指的是把浏览器当做一个对象来对待, 这个对象主要定义了与浏览器进行交互的法和接口。BOM 的核心是 window,而 window 对象具有双重角色,它既是通过 js 访问浏览器 窗口的一个接口,又是一个 Global(全局)对象。这意味着在网页 中定义的任何对象,变量和函数,都作为全局对象的一个属性或者方 法存在。window 对象含有 location 对象、navigator 对象、screen对象等子对象,并且 DOM 的最根本的对象 document 对象也是 BOM 的 window 对象的子对象。

16.聊聊 什么是函数尾调用,使用尾调用有什么好处?

尾调用指的是函数的最后一步调用另一个函数。代码执行是基于执行 栈的,所以当在一个函数里调用另一个函数时,会保留当前的执行上 下文,然后再新建另外一个执行上下文加入栈中。使用尾调用的话, 因为已经是函数的最后一步,所以这时可以不必再保留当前的执行上 下文,从而节省了内存,这就是尾调用优化。但是 ES6 的尾调用优 化只在严格模式下开启,正常模式是无效的。

你可能感兴趣的:(前端八股文【藏经阁】,javascript,前端)