george-es / Blog

My Blog
0 stars 0 forks source link

#83

Open george-es opened 3 years ago

george-es commented 3 years ago
george-es commented 3 years ago

写一个 mySetInterVal(fn, a, b),每次间隔 a,a+b,a+2b,...,a+nb 的时间,然后写一个 myClear,停止上面的 mySetInterVal

  function mySetInterVal(fn, a, b) {
      this.count = 0
      this.a = a
      this.b = b
      this.timer = -1
      this.start = () => {
          return () => {
              this.timer = setTimeout(() => {
                  fn()
                  this.count++
                  this.start()
              }, this.a + this.count * this.b)
          }
      }
      this.stop = () => {
          clearTimeout(this.timer)
          this.count = 0
      }
  }
  var t = new mySetInterVal(() => {console.log('test')},1000, 2000 );
  t.start();
  t.stop();

实现斐波那契数列

function fibonacciIterative(n) {
    if (n < 1) return 0;
    if (n <= 2) return 1;
    let fibNMinus1 = 0;
    let fibNMinus2 = 1;
    let fibN = n
    for (let i = 2; i < n; i++) {
        fibN = fibNMinus1 + fibNMinus2
        fibNMinus1 = fibNMinus2
        fibNMinus2 = fibN
    }
    return fibN
}

React 项目中有哪些细节可以优化?实际开发中都做过哪些性能优化?

React 最新版本解决了什么问题 加了哪些东西?

1)React 16.x的三大新特性 Time Slicing, Suspense,hooks

2)React16.8

3)React16.9

4)React16.13.0

说一下 Http 缓存策略,有什么区别,分别解决了什么问题

介绍防抖节流原理、区别以及应用,并用JavaScript进行实现

防抖:某个事件频繁触发,若一段事件后,该事件没有触发,则执行事件函数,整个过程事件只触发一次

function debounce(func, wait) {
    let timer = null
    return () => {
        if(timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(() => func.apply(this, arguments), wait)
    }
}

节流:某个事件频繁触发,事件并不会按照次数进行触发,而会按照固定的时间频率触发,整个过程,事件触发多次

function throttle(func, wait) {
    let timer = null
    return () => {
        if(!timer) {
            timer = setTimeout(() => {
                func.apply(this, argument)
                timer = null
            }, wait)
        }

    }
}

前端安全、中间人攻击

对闭包的看法,为什么要用闭包?说一下闭包原理以及应用场景

JS 数据类型有哪些,都有什么区别?

JS 数据类型分为两类,基础类型和引用类型

基础类型:string,number,boolean,undefined,null,symbol,bigint

复杂类型:function,object

区别:

什么是 BigInt 类型,它的优缺点是什么?解决了什么问题?应用场景是什么?

BigInt 是一种内置对象,它提供了一种方法用来表示超过 Number 类型最大范围的数(2 ^ 53 - 1),BigInt 可以表示任意大的整数

BigInt 也称为 JS 中的任意精度整型,可表示任意精度的整数值

可以用在一个整数后加 n 的方式定义 BigInt,或者用 BigInt()

const bigNum = 10n
const bn = BigInt('10')

null 和 undefined 的区别

相同点

不同点

调用函数时,应该提供的参数没有提供,该参数等于undefined。

函数没有返回值时,默认返回undefined。

对象没有赋值的属性,该属性的值为undefined。

判断 JS 数据类型的方法,以及它们的优缺点,如何精确判断数组类型

所以说typeof,toString 检测的是实例与数据类型之间的关系,instanceof 和 constructor 检测的是实例与构造函数之间的关系

隐式转换的场景和原则,如何避免或者巧妙使用

常见的会转换成这几个类型 string,number,boolean,

george-es commented 3 years ago

原型规则是什么?

原型链:将原型对象连起来就是原型链

image

手动实现 new

var new = (func) => {
    var o = Object.create(func.prototype)
    var k = func.call(o)
    if(typeof k === 'object') {
        return k
    } else {
        return o
    }
}

class 底层实现原理

词法作用域和动态作用域是什么?

词法作用域:函数作用域在函数定义的时候就决定了

动态作用域:函数作用域在函数调用时候才决定的

谈谈你对作用域和作用域链的理解

当访问一个变量时,会在当前作用域下寻找,若当前未找到对应的变量,则会沿着作用域链寻找

this 使用场景 8 种场景

理解堆栈溢出和内存泄漏的原理,如何防止?

什么是内存泄漏?

程序运行需要用到内存,只要程序提出需求,操作系统或运行时,就必须提供内存。

对于持续运行的服务进程,必须及时释放不再用到的内存,否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。

不再用到的内存,没有及时释放,就叫内存泄漏(memory leak)

垃圾回收机制

最常用的方法叫"引用计数",语言引擎有一张"引用表",保存了内存里面所有的资源的引用次数,如果一个值的引用次数是 0 ,就表示这个值不再用到,因此可以将这块内存释放。

如果一个值不再需要,引用数却不为0,垃圾回收机制无法释放这块内存,从而导致内存泄漏。

譬如说

const arr = [1,2,3,4]
console.log('hello world')

定义了一个 arr,会占用内存,此时引用计数为 1

const arr = [1,2,3,4]
console.log('hello world')
arr = null

此时将它置为 null,就解除了 arr 的引用,此时引用计数为 0,内存就释放出来了。

因此,并不是说有了垃圾回收机制,程序员就轻松了。还是需要关注内存占用:那些很占空间的值,一旦不再用到,你必须检查是否还存在对它们的引用。如果是的话,就必须手动解除引用。

内存泄漏的识别方法

怎样可以观察到内存泄漏呢?

经验是,如果连续五次垃圾回收之后,内存占用一次比一次大,就有内存泄漏。这就要求实时查看内存占用。

在 chrome 中,我们可以通过捕获观察内存是否平稳,如果逐渐升高代表泄漏了

image

内存泄漏出现的场景

模块化怎么用的?原理是什么?有什么优缺点

为何 try 里面放 returnfinally 还会执行,理解其内部机制

try-catch-finally 内部机制

try 语句包含了由一个或多个语句组成的 try 块,和至少一个 catch 块或一个 finally块

说说你对宏任务和微任务的理解

虽然 js 是单线程的,但是它可以执行同步和异步任务,这要归功于它的任务机制。同步任务不多解释,就是按照顺序去执行,而异步任务,是有一个优先级的,包括了宏任务和微任务。

宏任务:setTimeout,setInterval,setImmediate,I/O,UI,rendering

微任务:Promise(then,catch,finally),process,nextTick,MutationObserver

执行栈的执行逻辑是

image

说说对 EventLoop 的理解

如何在保证页面运行流畅的情况下处理海量数据

JavaScript 与 ECMAScript 的关系

JS 包括核心(ECMAScript)、文本对象模型(DOM)、浏览器模型(BOM)

也就是说 EMACScript 来源于 JavaScript,又反向作为 JavaScript 的标准。

['1', '2', '3'].map(parseInt) 引发的思考,了解了 parseInt 实现原理

一拿到这个题,我立刻脱口而出,答案 1,2,3,run 完后发现答案竟然是 [1, NaN, NaN]

带着疑虑,做出猜想,parseInt 可以接收 2 个参数,很可能就是第二个参数导致的,第二个参数传的是基数

于是把数加大,看能不能找出规律

['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'].map(parseInt)
// [ 1, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, 9, 11, 13 ]

就是基数搞的鬼,map 后,数组的下标成了基数,上面这行代码会被解析成

parseInt('1', 0)  // 1
parseInt('2', 1)  // NaN
parseInt('3', 2)  // NaN

这时围绕着基数,在想,什么是基数呢?应该是进制数了,随后摸索了下 parseInt 的实现原理,这就涉及进制转换原理了

parseInt("11",2)   // 返回 3  (2 + 1)
把 11 看成两个数 1 + 1,因为 1 都小于基数 2,所以 1 * 2^1 +1 * 2^0 = 2+1 = 3
parseInt("113",2)  // 返回 3 (2 + 1)
由于 3 大于 2 不属于 2 进制数,因此只计算前两位 1 * 2^1 +1 * 2^0 = 2+1 = 3
parseInt("131",2)  // 返回 2 (2)
由于 3 大于 2,因此计算规则是从第一个是2进制数的数开始到碰到第一个不是2进制数截止。
parseInt("311",2)  // 返回 NaN
由于 3 大于 2 不属于 2 进制,所以不往后计算了

同理其他进制也是这样计算的

george-es commented 3 years ago

介绍下 Set,Map,WeakSet,WeakMap 的区别和使用场景

模块化发展历程

模块化主要作用是用来抽离公共代码,隔离作用域,避免变量冲突。

常用的模块化方案:

const 和 let 声明会挂载到 window 上吗?

不会的,它有独立作用域

let a = 10
console.log(window.a) // undefined
// 等同于
(function() {
    var a = 10
})()

作用域题

var b = 10
(function b() {
    b = 20
    console.log(b) // [function b]
    console.log(window.b) // 10
})()

内部作用域,会先去查找是有已有变量 b 的声明,有就直接赋值 20,确实有,发现是具名函数,function b(){},拿此 b 做赋值,IIFE 无法进行赋值(内部机制,类似 const 定义的常量)所以无效

var a = 10;
(function () {
    console.log(a) // 10
})()

这里会到外层去取

var a = 10;
(function () {
    console.log(a) // undefined
    a = 5
    console.log(window.a) // 10
    var a = 20
    console.log(a) // 20
})()

以下代码会返回什么?

// 一
var obj = {
    '0': 10,
    'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj); // { '0': 1, '1': 2, push: [Function: push], length: 2 }

// 二
var obj = {
    '0': 10,
    'length': 8,
    'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj); // { '0': 10, '8': 1, '9': 2, length: 10, push: [Function: push] }

// 三
var obj = {
    '0': 10,
    'length': 8,
    'splice': Array.prototype.splice,
    'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
obj.splice(1, 1, 1)
console.log(obj); // {'0': 10, '1': 1, '8': 1, '9': 2, length: 10, splice: [Function: splice], push: [Function: push]}

push 这个方法如果对象上有 length 属性,length 属性会加 1 并且返回,若没有则创建它,这道题考的是类数组和 push 方法

箭头函数和普通函数区别是什么?构造函数可以使用 new 生成实例,箭头函数可以麽?

箭头函数是普通函数的简写形式,有以下几点区别