「offer来了」保姆级巩固你的js知识体系(4.0w字)

Posted 星期一研究室

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「offer来了」保姆级巩固你的js知识体系(4.0w字)相关的知识,希望对你有一定的参考价值。


「面试专栏」前端面试之javascript

🧐序言

大家都知道, js 在前端面试中的占比可以说是非常大了。基本上在每一场面试中,有 40% 以上的题都是 js 的题目。 js 不仅考察一个前端人的基础能力,更重要的是前端可以说是以 js 为本,所以也很考察我们的代码能力和逻辑思维。如果说在面试前端中 js 都不过关,那其实还是蛮危险的。

下面的这篇文章中,将讲解我整个秋招备试过程的所有题目。其中,有些知识点是一个很大的范围,但是放在面试系列中整理的话只能是概括性介绍,我将会以链接的方式,将我之前写的文章和其他相关模块的文章,放在题目后进行标注,方便大家更详细的了解当下模块的扩展知识点。

下面开始本文的讲解~📚

🥳思维导图环节

在真正开篇之前,先用一张思维导图来了解全文的内容。详情见下图👇

思维导图收入囊中了,就该开始来架起 js 的知识体系啦~

😏一、JS规范

1、说几条JavaScript的基本规范。

  • for-in 循环中的变量应该使用let关键字明确限定作用域,从而避免作用域污染。
for(let i in obj){
    
}
  • 比较布尔值/数值时,需用 === / !== 来比较;
  • switch 语句必须带有 default 分支;
  • 不要使用全局函数;
  • 使用对象字面量替代 new Array 这种形式,以下给出对象字面量的例子。
let person = {
	name:'张三',
	age:13,
	like:['打篮球','打排球']
}

2、对原生JavaScript的了解。

数据类型、运算、对象、 Function 、继承、闭包、作用域、原型链、事件、RegExpJSONAjaxDOMBOM 、内存泄漏、异步装载、模板引擎、前端MVC 、路由、模块化、CanvasECMAScript

3、说下对JS的了解吧。

是基于原型的动态语言,主要特性有this原型原型链

JS严格意义上来说分为:语言标准部分ECMAScript )+ 宿主环境部分

语言标准部分

  • 2015年发布 ES6 ,引入诸多特性,使得能够编写大型项目成为可能,标准自 2015年 之后以年号作为代号,每年一更。

宿主环境部分

  • 在浏览器宿主环境包括 DOM + BOM
  • Node ,宿主环境包括一些文件、数据库、网络、与操作系统的交互等

4、JS原生拖拽节点

  • 给需要拖拽的节点绑定 mousedownmousemovemouseup 事件。
  • mousedown 事件触发后,开始拖拽。
  • mousemove 时,需要通过 event.clientXclientY 获取拖拽位置,并实时更新位置
  • mouseup 时,拖拽结束。
  • 需要注意浏览器边界值,设置拖拽范围

5、谈谈你对ES6的理解

  • 新增模板字符串(为 JavaScript 提供了简单的字符串插值功能)。
  • 箭头函数。
  • for-of(用来遍历数据——例如数组中的值)。
  • arguments 对象可以被不确定的参数和默认参数完美替代。
  • ES6promise 对象纳入规范,提供了原生的 promise 对象。
  • 增加了 letconst 命令,用来声明变量。
  • 还有就是引入 module 模块的概念。

6、知道ES6的class嘛?

ES6 中的 class 是,为这个类的函数对象直接添加方法,而不是加在这个函数对象的原型对象上。

7、说说你对AMD和Commonjs的理解

  • CommonJS 是服务器端模块的规范,Node.js 采用了这个规范。
  • CommonJS 规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD 规范则是非同步加载模块,允许指定回调函数。
  • AMD 推荐的风格通过返回一个对象作为模块对象。CommonJS 的风格则是通过对 module.exportsexports 的属性赋值来达到暴露模块对象的目的。

8、如何理解前端模块化

前端模块化就是复杂的文件编程中一个个独立的模块,比如js文件等等,分成独立的模块有利于重用(复用性)和维护(版本迭代),这样会引来模块之间相互依赖的问题,所以有了commonJS规范,AMD,CMD规范等等,以及用于js打包(变异等处理)的工具webpack。

9、面向对象编程思想

  • 基本思想是使用对象,类,继承,封装等基本概念来进行程序设计;
  • 易维护;
  • 易扩展;
  • 开发工作的重用性、继承性高,降低重复工作量;
  • 缩短了开发周期。

10、用过 TypeScript 吗?它的作用是什么?

TypeScriptJS 添加类型支持,以及提供最新版的 ES 语法的支持,有利于团队协作和排错,开发大型项目。

11、PWA使用过吗?serviceWorker的使用原理是啥?

渐进式网络应用(PWA)是谷歌在 2015年底 提出的概念。基本上算是web应用程序,但在外观和感觉上与 原生app 类似。支持 PWA 的网站可以提供脱机工作推送通知设备硬件访问等功能。

Service Worker 是浏览器在后台独立于网页运行的脚本,它打开了通向不需要网页或用户交互的功能的大门。 现在,它们已包括如推送通知和后台同步等功能。 将来, Service Worker 将会支持如定期同步或地理围栏等其他功能。

:渐进式网络应用 Progressive Network Application

😲二、数据类型

1、问:0.1+0.2 === 0.3吗?为什么?

在正常的数学逻辑思维中, 0.1+0.2=0.3 这个逻辑是正确的,但是在 JavaScript0.1+0.2 !== 0.3 ,这是为什么呢?这个问题也会偶尔被用来当做面试题来考查面试者对 JavaScript 的数值的理解程度。

0.1 + 0.2 == 0.3 // false

JS 中,二进制的浮点数 0.10.2 并不是精确的,所以它们相加的结果并非正好等于 0.3 ,而是一个比较接近 0.3 的数字 0.30000000000000004 ,所以条件判断结果为 false

原因在于在 JS 当中,采用的是 IEEE 754 的双精度标准,所以计算机内部在存储数据编码的时候,0.1在计算机内部不是精确的 0.1 ,而是一个有舍入误差的 0.1 。当代码被编译或解析后, 0.1 已经被四舍五入成一个与之很接近的计算机内部数字,以至于计算还没开始,一个很小的舍入错误就已经产生了。这也就是 0.1 + 0.2 不等于 0.3 的原因。

那如何避免这样的问题?

最常用的方法就是将浮点数转化成整数计算,因为整数都是可以精确表示的。

通常就是把计算数字提升10的N次方倍再除以 10N 次方,一般都用 1000 就行了。

(0.1*1000 + 0.2*1000)/1000 == 0.3 //true

2、js数据类型有哪些?具体存在哪里?判断方式是什么?

(1)js数据类型

js 数据类型包括基本数据类型引用数据类型

(2)具体存放在哪里?

基本数据类型:

基本数据类型,是指 NumerBooleanStringnullundefinedSymbol (ES6新增的)、 BigInt(ES2020) 等值,它们在内存中都是存储在栈中的,即直接访问该变量就可以得到存储在中的对应该变量的值。

若将一个变量的值赋值给另一个变量,则这两个变量在内存中是独立的,修改其中任意一个变量的值,不会影响另一个变量。这就是基本数据类型。

引用数据类型:

那引用数据类型呢,是指 ObjectArrayFunction 等,他们在内存中是存在于栈和堆当中的,即我们要访问到引用类型的值时,需要先访问到该变量在中的地址(指向堆中的值),然后再通过这个地址,访问到存放在中的数据。这就是引用数据类型。

(3) 常用判断方式:typeof、instanceof、===

1)typeof:

定义:返回数据类型的字符串表达(小写)

用法:typeof + 变量

可以判断

  • undefined/ 数值 / 字符串 / 布尔值 / function (返回 ‘undefined’ / ‘number’ / ‘string’ / ‘boolean’ / ‘function’)

  • null与object 、object与array (null、array、object都会返回 ‘object’ )

<script type="text/javascript">
    console.log(typeof "Tony");                // 返回 string 
    console.log(typeof 5.01);                  // 返回 number
    console.log(typeof false);                 // 返回 boolean
    console.log(typeof undefined);             // 返回 undefined
    console.log(typeof null);                  // 返回 object
    console.log(typeof [1,2,3,4]);             // 返回 object
    console.log(typeof {name:'John', age:34}); // 返回 object
</script>

2)instanceof:

定义:判断对象的具体类型

用法b instanceof A →表明 b 是否是 A 的实例对象

可以判断

专门用来判断对象数据的类型: Object , ArrayFunction

判断 StringNumberBoolean 这三种类型的数据时,直接赋值为 false ,调用构造函数创建的数据为 true

<script type="text/javascript">
    let str = new String("hello world")     //console.log(str instanceof String);  → true
    str = "hello world"                     //console.log(str instanceof String);  → false

    let num = new Number(44)                //console.log(num instanceof Number);  → true
    num = 44                                //console.log(num instanceof Number);  → false

    let bool = new Boolean(true)            //console.log(bool instanceof Boolean);  → true
    bool = true                             //console.log(bool instanceof Boolean);  → false

</script>
<script type="text/javascript">
    var items = []; 
    var object = {}; 
    
    function reflect(value) { 
        return value;
    } 
 
    console.log(items instanceof Array);        // true 
    console.log(items instanceof Object);       // true 
    console.log(object instanceof Object);      // true 
    console.log(object instanceof Array);       // false 
    console.log(reflect instanceof Function);   // true 
    console.log(reflect instanceof Object);     // true 

3)===:

可以判断undefinednull

<script type="text/javascript">
    let str;
    console.log(typeof str, str === undefined);   //'undefined', true

    let str2 = null;
    console.log(typeof str2, str2 === null); // 'object', true

</script>

3、什么是浅拷贝?什么是深拷贝?说明并分别写出代码。

(1)浅拷贝

所谓浅拷贝,就是一个变量赋值给另一个变量,其中一个变量的值改变,则两个变量的值都变了,即对于浅拷贝来说,是数据在拷贝后,新拷贝的对象内部仍然有一部分数据会随着源对象的变化而变化。

// 分析
function shallowCopy(obj){
    let copyObj = {};
    for(let i in obj){
        copyObj[i] = obj[i];
    }
    return copyObj;
}

// 实例
let a = {
    name: '张三',
    age: 19,
    like: ['打篮球', '唱歌', '跳舞']
}

let b = shallowCopy(a);

a.name = '李四';
a.like[0] = '打打乒乓球';
console.log(a);
console.log(b);

(2)深拷贝

定义:深拷贝 就是,新拷贝的对象内部所有数据都是独立存在的,不会随着源对象的改变而改变。

深拷贝有两种方式:递归拷贝和利用JSON函数进行深拷贝。

  • 递归拷贝的实现原理是:对变量中的每个元素进行获取,若遇到基本类型值,直接获取;若遇到引用类型值,则继续对该值内部的每个元素进行获取。
  • JSON深拷贝的实现原理是:将变量的值转为字符串形式,然后再转化为对象赋值给新的变量。

局限性:深拷贝的局限性在于,会忽略 undefined ,不能序列化函数,不能解决循环引用的对象。

递归拷贝方式实现代码:

// 分析
function deepCopy(obj){
    // 判断是否为引用数据类型
    if(typeof obj === 'object'){
        let result = obj.constructor === Array ? [] : {};
		// 对引用类型继续进行遍历,如果遍历没有结束的话
        for(let i in obj){
            result[i] =  typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i];
        }

        return result;
    }
    // 为基本数据类型,直接赋值返回
    else{
        return obj;
    }
}

// 实例 - 利用递归函数做深拷贝
let c = {
    name:'张三',
    age:12,
    like:[
        '打乒乓球',
        '打羽毛球',
        '打太极'
    ]
}

let d = deepCopy(c);

c.name = '李四';
c.like[0] = '打篮球';
console.log(c);
console.log(d);

JSON深拷贝实现代码:

// 实例 - 利用json函数做深拷贝
let e = {
    name: '张三',
    age: 19,
    like:['打羽毛球', '唱歌', '跳舞']
}

let f = JSON.parse(JSON.stringify(e));

// 注意: JSON函数做深度拷贝时不能拷贝正则,Date,方法函数等

e.name = '李四';
e.like[0] = '打乒乓球';

// console.log(e);
// console.log(f);

这里可以在参考我之前写过的一篇文章辅助理解👉栈在前端中的应用,顺便再了解下深拷贝和浅拷贝!

4、JS整数是怎么表示的?

JS整数通过 Number 类型来表示,遵循 IEEE 754 标准,通过 64位 来表示一个数字,即 1+11+52 (符号位+指数位+小数部分有效位),最大安全数字是 253 - 1,对应 16位 十进制数。

:1位十进制数对应4位二进制数

5、Number的存储空间是多大?如果后台发送了一个超过最大数字怎么办?

Math.pow(2,53),53为有效数字;如果后台发送一个超过最大数字,会发生截断,等于 JS 能支持的最大安全数字 253 - 1。

6、NAN是什么,用typeof会输出什么?

Not a Number,表示非数字。

typeof NaN === 'number'; //true

7、Symbol有什么用处?

  • 可以用来表示一个独一无二的变量,防止命名冲突
  • 除此之外, Symbol 还可以用来模拟私有属性。

8、null,undefined的区别

  • undefined 表示不存在这个值。
  • undefined 是一个表示“无”的原始值或者说表示“缺少值”,就是此处应该有一个值,但是还没有定义。尝试读取时就会返回 undefined
  • 例如变量被声明了,但没有赋值时,就等于 undefined
  • null 表示一个对象被定义了,值为“空值”。
  • null 是一个对象(空对象,没有任何属性和方法)。
  • 例如作为函数的参数时,表示该函数的参数不是对象。
  • 在验证 null 时,一定要使用 === ,因为 == 无法区分 nullundefined

9、JS隐式转换,显示转换

一般非基础类型进行转换时会调用valueOf,如果 valueOf 无法返回基本类型值,就会调用toString

(1)字符串和数字

  • “+”操作符,如果有一个为字符串,那么都转化到字符串然后执行字符串拼接。
  • “-”操作符,转换为数字,相减(-a, a*1, a/1)都能进行隐式强制类型转换。
[] + {} 和 {} + []

(2)布尔值到数字

  • 1 + true = 2;
  • 1 + false = 1;

(3)转换为布尔值

  • for中第二个
  • while
  • if
  • 三元表达式
  • || (逻辑或)和 &&(逻辑与)左边的操作个数

(4)符号

  • 不能被转换为数字
  • 能被转换为布尔值(都是true)
  • 可以被转换成字符串“Symbol(cool)”

(5)宽松相等和严格相等

宽松相等允许进行强制类型转换,而严格相等不允许。

①字符串与数字

  • 转换为数字然后比较

②其他类型与布尔类型

  • 先把布尔类型转换为数字,然后继续进行比较

③对象与非对象

  • 执行对象的 ToPrimitive (对象)然后继续进行比较

④假值列表

  • undefined
  • null
  • false
  • +0,-0,NaN
  • “”

10、介绍下js有哪些内置对象

  • ObjectJavascript 中所有对象的父对象;
  • 其他数据封装类对象:ObjectArrayBooleanNumberString
  • 其他对象:FunctionArgumentsMathDateRegExpError

11、js有哪些方法定义对象

  • 对象字面量:let obj = {}
  • 构造函数:let obj = new Object()
  • Object.create():let obj = Object.create(object.prototype)

12、如何判断一个对象是不是空对象?

Object.keys(obj).length === 0

13、手写题:获取url参数getUrlParams(url)

//封装函数getUrlParams, 将URL地址的参数解析为对象
function getUrlParams(url){
    let obj = {};

    if(url.indexOf('?') === -1){
        return obj;
    }

    let first_res = url.split('?')[1];
    let second_res = first_res.split('&');
    
    for(let i in second_res){
        third = second_res[i].split('=');
        obj[third[0]] = third[1];
    }
    return obj;
}


// 测试代码

let URL = 'https://www.sogou.com/web?ie=UTF-8&query=搜索内容&_em=3';
console.log(getUrlParams(URL));

14、数组能够调用的函数有哪些?

  • push 向数组尾部添加元素
  • pop 删除并返回数组最后一个元素
  • splice 添加/删除元素
  • slice 返回选定的元素
  • shift 删除第一个元素并返回
  • unshift 向数组开头添加一个或更多元素,并返回新长度
  • sort 对数组元素进行排序
  • find 返回通过测试的数组的第一个元素
  • findIndex
  • map/filter/reduce 等函数式编程方法
  • 原型链上的方法:toString/valueOf

15、函数中的arguments是数组吗?类数组转数组的方法了解一下?

是类数组,是属于鸭子类型的范畴,只是长得像数组。

  • … 运算符
  • Array.from
  • Array.prototype.slice.apply(arguments)

16、手写题:如何判断数组类型?

// 方法一:instanceof方法
let arr = [1, 2, 3];
console.log(arr instanceof Array);

// 方法二:constructor方法
let arr = [1, 2, 3];
console.log(arr.constructor === Array);

// 方法三:isArray方法
let arr = [1, 2, 3];
console.log(Array.isArray(arr));

// 方法四:Object.prototype方法
let arr = [1, 2, 3];
console.log(Object.prototype.toString.call(arr) === '[object Array]');

// 方法五:Array.__proto__方法
let arr = [1, 2, 3];
console.log(arr.__proto__ === Array.prototype);

// 方法六:Object.getPrototypeOf方法
let arr = [1, 2, 3];
console.log(Object.getPrototypeOf(arr) === Array.prototype);

// 方法七:Array.prototype.isPrototypeOf方法
let arr = [1, 2, 3];
console.log(Array.prototype.isPrototypeOf(arr「offer来了」2种递进学习思维,24道计网题目,保姆级巩固你的计网知识体系

「offer来了」2种递进学习思维,24道计网题目,保姆级巩固你的计网知识体系

「offer来了」从基础到进阶原理,从vue2到vue3,48个知识点保姆级带你巩固vuejs知识体系

「offer来了」从基础到进阶原理,从vue2到vue3,48个知识点保姆级带你巩固vuejs知识体系

「offer来了」浏览器原理被问懵?5大知识板块巩固你的http知识体系(3.6w字)

「offer来了」浏览器原理被问懵?5大知识板块巩固你的http知识体系(3.6w字)