面试官:说说JavaScript中的事件模型
面试官:说说JavaScript中的事件模型
一、事件与事件流javascript中的事件,可以理解就是在HTML文档或者浏览器中发生的一种交互操作,使得网页具备互动性, 常见的有加载事件、鼠标事件、自定义事件等
由于DOM是一个树结构,如果在父子节点绑定事件时候,当触发子节点的时候,就存在一个顺序问题,这就涉及到了事件流的概念
事件流都会经历三个阶段:
事件捕获阶段(capture phase)
处于目标阶段(target phase)
事件冒泡阶段(bubbling phase)
事件冒泡是一种从下往上的传播方式,由最具体的元素(触发节点)然后逐渐向上传播到最不具体的那个节点,也就是DOM中最高层的父节点
12345678910<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8"> <title>Event Bubbling</title> </hea ...
面试官:解释下什么是事件代理?应用场景?
面试官:解释下什么是事件代理?应用场景?
一、是什么事件代理,俗地来讲,就是把一个元素响应事件(click、keydown……)的函数委托到另一个元素
前面讲到,事件流的都会经过三个阶段: 捕获阶段 -> 目标阶段 -> 冒泡阶段,而事件委托就是在冒泡阶段完成
事件委托,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,而不是目标元素
当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数
下面举个例子:
比如一个宿舍的同学同时快递到了,一种笨方法就是他们一个个去领取
较优方法就是把这件事情委托给宿舍长,让一个人出去拿好所有快递,然后再根据收件人一一分发给每个同学
在这里,取快递就是一个事件,每个同学指的是需要响应事件的 DOM 元素,而出去统一领取快递的宿舍长就是代理的元素
所以真正绑定事件的是这个元素,按照收件人分发快递的过程就是在事件执行中,需要判断当前响应的事件应该匹配到被代理元素中的哪一个或者哪几个
二、应用场景如果我们有一个列表,列表之中有大量的列表项,我们需要在点击列表项的时候 ...
面试官:说说你对事件循环的理解
面试官:说说你对事件循环的理解
一、是什么首先,JavaScript 是一门单线程的语言,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环
在JavaScript中,所有的任务都可以分为
同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
异步任务:异步执行的任务,比如ajax网络请求,setTimeout 定时函数等
同步任务与异步任务的运行流程图如下:
从上面我们可以看到,同步任务进入主线程,即主执行栈,异步任务进入任务队列,主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。上述过程的不断重复就事件循环
二、宏任务与微任务如果将任务划分为同步任务和异步任务并不是那么的准确,举个例子:
1234567891011121314console.log(1)setTimeout(()=>{ console.log(2)}, 0)new Promise((resolve, reject)=>{ console.log('new Pr ...
面试官:Javascript中如何实现函数缓存?函数缓存有哪些应用场景?
面试官:Javascript中如何实现函数缓存?函数缓存有哪些应用场景?
一、是什么函数缓存,就是将函数运算过的结果进行缓存
本质上就是用空间(缓存存储)换时间(计算过程)
常用于缓存数据计算结果和缓存对象
1234const add = (a,b) => a+b;const calc = memoize(add); // 函数缓存calc(10,20);// 30calc(10,20);// 30 缓存
缓存只是一个临时的数据存储,它保存数据,以便将来对该数据的请求能够更快地得到处理
二、如何实现实现函数缓存主要依靠闭包、柯里化、高阶函数,这里再简单复习下:
闭包闭包可以理解成,函数 + 函数体内可访问的变量总和
123456789(function() { var a = 1; function add() { const b = 2 let sum = b + a console.log(sum); // 3 } add()})()
add 函数本身,以及其内部可 ...
面试官:说说你对函数式编程的理解?优缺点?
面试官:说说你对函数式编程的理解?优缺点?
一、是什么函数式编程是一种”编程范式”(programming paradigm),一种编写程序的方法论
主要的编程范式有三种:命令式编程,声明式编程和函数式编程
相比命令式编程,函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而非设计一个复杂的执行过程
举个例子,将数组每个元素进行平方操作,命令式编程与函数式编程如下
12345678// 命令式编程var array = [0, 1, 2, 3]for(let i = 0; i < array.length; i++) { array[i] = Math.pow(array[i], 2)}// 函数式方式[0, 1, 2, 3].map(num => Math.pow(num, 2))
简单来讲,就是要把过程逻辑写成函数,定义好输入参数,只关心它的输出结果
即是一种描述集合和集合之间的转换关系,输入通过函数都会返回有且只有一个输出值
可以看到,函数实际上是一个关系,或者说是一种映 ...
面试官:Javascript如何实现继承?
面试官:Javascript如何实现继承?
一、是什么继承(inheritance)是面向对象软件技术当中的一个概念。
如果一个类别B“继承自”另一个类别A,就把这个B称为“A的子类”,而把A称为“B的父类别”也可以称“A是B的超类”
继承的优点
继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码
在子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能
虽然JavaScript并不是真正的面向对象语言,但它天生的灵活性,使应用场景更加丰富
关于继承,我们举个形象的例子:
定义一个类(Class)叫汽车,汽车的属性包括颜色、轮胎、品牌、速度、排气量等
1234567class Car{ constructor(color,speed){ this.color = color this.speed = speed // ... }}
由汽车这个类可以派生出“轿车”和“货车”两个类,在汽车的基础属性上,为轿车 ...
面试官:说说你了解的js数据结构?
面试官:说说你了解的js数据结构?什么是数据结构?数据结构是计算机存储、组织数据的方式。数据结构意味着接口或封装:一个数据结构可被视为两个函数之间的接口,或者是由数据类型联合组成的存储内容的访问方法封装。
我们每天的编码中都会用到数据结构数组是最简单的内存数据结构下面是常见的数据结构:
数组(Array)
栈(Stack)
队列(Queue)
链表(Linked List)
字典
散列表(Hash table)
树(Tree)
图(Graph)
堆(Heap)
数组(Array)数组是最最基本的数据结构,很多语言都内置支持数组。数组是使用一块连续的内存空间保存数据,保存的数据的个数在分配内存的时候就是确定的。
在日常生活中,人们经常使用列表:待办事项列表、购物清单等。
而计算机程序也在使用列表,在下面的条件下,选择列表作为数据结构就显得尤为有用:数据结构较为简单不需要在一个长序列中查找元素,或者对其进行排序反之,如果数据结构非常复杂,列表的作用就没有那么大了。
栈(Stack)栈是一种遵循后进先出(LIFO)原则的有序集合在栈里,新元素都接近栈顶,旧元素都接近栈底。每次加入新的元素 ...
面试官:说说 Javascript 数字精度丢失的问题,如何解决?
面试官:说说 Javascript 数字精度丢失的问题,如何解决?
一、场景复现一个经典的面试题
10.1 + 0.2 === 0.3 // false
为什么是false呢?
先看下面这个比喻
比如一个数 1÷3=0.33333333……
3会一直无限循环,数学可以表示,但是计算机要存储,方便下次取出来再使用,但0.333333…… 这个数无限循环,再大的内存它也存不下,所以不能存储一个相对于数学来说的值,只能存储一个近似值,当计算机存储后再取出时就会出现精度丢失问题
二、浮点数“浮点数”是一种表示数字的标准,整数也可以用浮点数的格式来存储
我们也可以理解成,浮点数就是小数
在JavaScript中,现在主流的数值类型是Number,而Number采用的是IEEE754规范中64位双精度浮点数编码
这样的存储结构优点是可以归一化处理整数和小数,节省存储空间
对于一个整数,可以很轻易转化成十进制或者二进制。但是对于一个浮点数来说,因为小数点的存在,小数点的位置不是固定的。解决思路就是使用科学计数法,这样小数点位置就固定了
而计算机只能用二进制(0或1)表示,二进制转换为科 ...
面试官:说说 JavaScript 中内存泄漏的几种情况?
面试官:说说 JavaScript 中内存泄漏的几种情况?
一、是什么内存泄漏(Memory leak)是在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存
并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费
程序的运行需要内存。只要程序提出要求,操作系统或者运行时就必须供给内存
对于持续运行的服务进程,必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃
在C语言中,因为是手动管理内存,内存泄露是经常出现的事情。
123456char * buffer;buffer = (char*) malloc(42);// Do something with bufferfree(buffer);
上面是 C 语言代码,malloc方法用来申请内存,使用完毕之后,必须自己用free方法释放内存。
这很麻烦,所以大多数语言提供自动内存管理,减轻程序员的负担,这被称为”垃圾回收机制”
二、垃圾回收机制Javascript 具有自动垃圾回收机制(GC:Gar ...
面试官:说说new操作符具体干了什么?
面试官:说说new操作符具体干了什么?
一、是什么在JavaScript中,new操作符用于创建一个给定构造函数的实例对象
例子
12345678910function Person(name, age){ this.name = name; this.age = age;}Person.prototype.sayName = function () { console.log(this.name)}const person1 = new Person('Tom', 20)console.log(person1) // Person {name: "Tom", age: 20}t.sayName() // 'Tom'
从上面可以看到:
new 通过构造函数 Person 创建出来的实例可以访问到构造函数中的属性
new 通过构造函数 Person 创建出来的实例可以访问到构造函数原型链中的属性(即实例与构造函数通过原型链连接了起来)
现在在构 ...