面试官: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 创建出来的实例可以访问到构造函数原型链中的属性(即实例与构造函数通过原型链连接了起来)
现在在构 ...
面试官:JavaScript原型,原型链 ? 有什么特点?
面试官:JavaScript原型,原型链 ? 有什么特点?
一、原型JavaScript 常被描述为一种基于原型的语言——每个对象拥有一个原型对象
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾
准确地说,这些属性和方法定义在Object的构造器函数(constructor functions)之上的prototype属性上,而非实例对象本身
下面举个例子:
函数可以有属性。 每个函数都有一个特殊的属性叫作原型prototype
12function doSomething(){}console.log( doSomething.prototype );
控制台输出
123456789101112{ constructor: ƒ doSomething(), __proto__: { constructor: ƒ Object(), hasOwnProperty: ƒ hasOwnProp ...
面试官:JavaScript中执行上下文和执行栈是什么?
面试官:JavaScript中执行上下文和执行栈是什么?
一、执行上下文简单的来说,执行上下文是一种对Javascript代码执行环境的抽象概念,也就是说只要有Javascript代码运行,那么它就一定是运行在执行上下文中
执行上下文的类型分为三种:
全局执行上下文:只有一个,浏览器中的全局对象就是 window 对象,this 指向这个全局对象
函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文
Eval 函数执行上下文: 指的是运行在 eval 函数中的代码,很少用而且不建议使用
下面给出全局上下文和函数上下文的例子:
紫色框住的部分为全局上下文,蓝色和橘色框起来的是不同的函数上下文。只有全局上下文(的变量)能被其他任何上下文访问
可以有任意多个函数上下文,每次调用函数创建一个新的上下文,会创建一个私有作用域,函数内部声明的任何变量都不能在当前函数作用域外部直接访问
二、生命周期执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 回收阶段
创建阶段创建阶段即当函数被调用,但未执行任何其内部代码之前
创建阶段做了三件 ...
面试官:说说你对作用域链的理解
面试官:说说你对作用域链的理解
一、作用域作用域,即变量(变量作用域又称上下文)和函数生效(能被访问)的区域或集合
换句话说,作用域决定了代码区块中变量和其他资源的可见性
举个例子
12345function myFunction() { let inVariable = "函数内部变量";}myFunction();//要先执行这个函数,否则根本不知道里面是啥console.log(inVariable); // Uncaught ReferenceError: inVariable is not defined
上述例子中,函数myFunction内部创建一个inVariable变量,当我们在全局访问这个变量的时候,系统会报错
这就说明我们在全局是无法获取到(闭包除外)函数内部的变量
我们一般将作用域分成:
全局作用域
函数作用域
块级作用域
全局作用域任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问
1234567// 全局变量var greeting = ...