dashengzi66 / note

学习笔记
0 stars 0 forks source link

前端面试 #3

Open dashengzi66 opened 3 years ago

dashengzi66 commented 3 years ago

请找出字符串中连续出现最多的字符和个数

const str1 = 'abcaakjbb' 
const str2 = 'abbkejsbcccwqaa'
function getMax(str) {
  // \1指的是括号中匹配的内容, .匹配除换行符(\n、\r)之外的任何单个字符
  const match = str.match(/(.)\1+/g);
  match.sort((x,y) => y.length - x.length);
  const len = match[0].length;
  const obj = {};
  for(let item of match) {
    if(item.length <len) {
      break
    }else{
      obj[item[0]] = len
    }
  }
  return obj
}
// 输出 {a: 2, d: 2}
console.log(getMax(str1))
// 输出 {c:3}
console.log(getMax(str2))

去重思维

let str = "zhufengpeixunzhoulaoshi";
let obj = {};
[].forEach.call(str, char => {
    if (typeof obj[char] !== "undefined") {
        obj[char]++;
        return;
    }
    obj[char] = 1;
});
let max = 1,
    res = [];
for (let key in obj) {
    let item = obj[key];
    item > max ? max = item : null;
}
for (let key in obj) {
    let item = obj[key];
    if (item === max) {
        res.push(key);
    }
}
console.log(`出现次数最多的字符:${res},出现了${max}次`);

排序

let str = "zhufengpeixunzhoulaoshi";
str = str.split('').sort((a, b) => a.localeCompare(b)).join('');
// console.log(str);//=>"aeefghhhiilnnoopsuuuxzz"
let ary = str.match(/([a-zA-Z])\1+/g).sort((a, b) => b.length - a.length);
// console.log(ary); //=>["hhh", "uuu", "ee", "ii", "nn", "oo", "zz"]
let max = ary[0].length,
    res = [ary[0].substr(0, 1)];
for (let i = 1; i < ary.length; i++) {
    let item = ary[i];
    if (item.length < max) {
        break;
    }
    res.push(item.substr(0, 1));
}
console.log(`出现次数最多的字符:${res},出现了${max}次`);

从最大到最小去试找

let str = "zhufengpeixunzhoulaoshi",
    max = 0,
    res = [],
    flag = false;
str = str.split('').sort((a, b) => a.localeCompare(b)).join('');
for (let i = str.length; i > 0; i--) {
    let reg = new RegExp("([a-zA-Z])\\1{" + (i - 1) + "}", "g");
    str.replace(reg, (content, $1) => {
        res.push($1);
        max = i;
        flag = true;
    });
    if (flag) break;
}
console.log(`出现次数最多的字符:${res},出现了${max}次`);
dashengzi66 commented 3 years ago

实现浅拷贝的方式

contact

const originArray = [1,2,3,4,5];
const cloneArray = originArray.concat();
console.log(cloneArray === originArray); // false
cloneArray.push(6); // [1,2,3,4,5,6]
console.log(originArray); [1,2,3,4,5];

总结:concat 只是对数组的第一层进行深拷贝

slice

const originArray = [1,2,3,4,5];
const cloneArray = originArray.slice();
console.log(cloneArray === originArray); // false
cloneArray.push(6); // [1,2,3,4,5,6]
console.log(originArray); [1,2,3,4,5];

总结:slice 只是对数组的第一层进行深拷贝

Object.assign()

let obj = {
   'name': 'zs',
  'age': '18'
}
let obj2=Object.assign({},newObj)

总结:Object.assign() 拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值

... 展开运算符

const originArray = [1,2,3,4,5,[6,7,8]];
const originObj = {a:1,b:{bb:1}};
const cloneArray = [...originArray];
cloneArray[0] = 0;
cloneArray[5].push(9);
console.log(originArray); // [1,2,3,4,5,[6,7,8,9]]
const cloneObj = {...originObj};
cloneObj.a = 2;
cloneObj.b.bb = 2;
console.log(originObj); // {a:1,b:{bb:2}}

总结:... 实现的是对象第一层的深拷贝。后面的只是拷贝的引用值

对象的浅拷贝

dashengzi66 commented 3 years ago

写一个算法求多个数组之间的交集

function intersection(...arrays) {
  const len = arrays.length
  if(len < 2){
      return len ? arrays[0] : []
   }

  let result = arrays.shift()
   console.log(result)
  arrays.forEach(arr => {
    result = result.filter(item => arr.includes(item))
  })
  return result
}

const arr1 = [1,2,3,4,5]
const arr2 = [4,2,1,5,6,7]
const arr3 = [2,4,7,8,3]

// 输出 [2,4]
console.log(intersection(arr1,arr2,arr3))
dashengzi66 commented 3 years ago

set应用场景

// 数组去重 let arr = [1, 1, 2, 3]; let unique = [... new Set(arr)];

let a = new Set([1, 2, 3]); let b = new Set([4, 3, 2]);

// 并集 let union = [...new Set([...a, ...b])]; // [1,2,3,4]

// 交集 let intersect = [...new Set([...a].filter(x => b.has(x)))]; [2,3]

// 差集 let difference = Array.from(new Set([...a].filter(x => !b.has(x)))); [1]

dashengzi66 commented 3 years ago

防抖

指触发事件后,在 n 秒内函数只能执行一次,如果触发事件后在 n 秒内又触发了事件,则会重新计算函数延执行时间

// 第一版(最简易版)
function debounce(func, wait) {
    var timeout;
    return function () {
        clearTimeout(timeout)
        timeout = setTimeout(func, wait);
    }
}
//第二版(解决this和event)
function debounce(func, wait) {
    var timeout;
    return function () {
        var context = this;
        var args = arguments;
        clearTimeout(timeout)
        timeout = setTimeout(function(){
            func.apply(context, args)
        }, wait);
    }
}
//第三版(立即执行版)
function debounce(func, wait, immediate) {
    var timeout;
    return function () {
        var context = this;
        var args = arguments;
        if (timeout) clearTimeout(timeout);
        if (immediate) {
            // 如果已经执行过,不再执行
            var callNow = !timeout;
            timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }
}
//大裤衩版
function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result
  const later = function() {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp
    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }
  return function(...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在,重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }

    return result
  }
}
dashengzi66 commented 3 years ago

手写bind

Function.prototype.bind2 = function (context){
   if (typeof this !== "function") {
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);
    var fNOP = function () {};
    var fBound = function () {
        var bindArgs = Array.prototype.slice.call(arguments);
        return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
    }
    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();
    return fBound;

}
dashengzi66 commented 3 years ago

String相关

let a = 10+null+true+[]+undefined+'珠峰'+null+[]+10+false console.log(a) // '11undefined珠峰null10false'

dashengzi66 commented 3 years ago

数据类型检测

typeof

constructor

Object.prototype.toString.call([value])

jQuery中数据类型分析

  (function () {
        var class2type = {};
        var toString = class2type.toString; //=>Object.prototype.toString
        // 设置数据类型的映射表
        ["Boolean", "Number", "String", "Function", "Array", "Date", "RegExp", "Object", "Error", "Symbol"].forEach(
          name => {
            class2type[`[object ${name}]`] = name.toLowerCase();
          })
        console.log(class2type)
        function toType(obj) {
          // 传递的值是null或者undefined,就返回对应的字符串
          if (obj == null) {
            return obj + "";
          }
          // 基本数据类型采用typeof检测
          return typeof obj === "object" || typeof obj === "function" ?
            class2type[toString.call(obj)] || "object" :
            typeof obj;
        }
        window.toType = toType;
      })()
dashengzi66 commented 3 years ago

手写forEach

Array.prototype.forEach = function forEach(callback, context) { // this -> arr let self = this, i = 0, len = self.length; context = context == null ? window : context; for (; i < len; i++) { console.log(1) typeof callback === 'function' ? callback.call(context, self[i], i) : null; } } let arr = new Array(10).fill(0) arr.forEach((item,i)=>{ console.log(item); })

dashengzi66 commented 3 years ago

this

dashengzi66 commented 3 years ago

promise

async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); } async function async2() { console.log("async2"); } async1(); setTimeout(() => { console.log("timeout"); }, 0); new Promise(function (resolve) { console.log("promise1"); resolve(); }).then(function () { console.log("promise2"); });

dashengzi66 commented 3 years ago

link和@import的区别

dashengzi66 commented 3 years ago

JS中验证两个值是否相等

  1. ==:相等(如果两边的类型不一样,首先会隐式转化为相同的类型,然后再做比较) 1>对象==字符串 对象->字符串 2>null==undefined ->true(三个符号是不相等的),但是null/undefined和其它任何值都不会相等 3>NaN==NaN ->false 4>Symbol()==Symbol() ->false 5>剩余的情况(例如:对象==数字、字符串==布尔...)都是要转换为数字,再进行比较的
  2. ===:绝对相等(要求两边的类型和值都要相等,例如:switch case)
  3. Object.is([val],[val]):判断两个值是否为同一个值
dashengzi66 commented 3 years ago

ES版本新加内容

dashengzi66 commented 3 years ago

什么是MVVM,MVVM和MVC的区别?

MVVM 定义:MVVM是Model-View-ViewModel的简写,即模型-视图-视图模型【模型】指的是指的是后端传递的数据,视图】指的是所看到的页面。【视图模型】mvvm模式的核心,它是连接view和model的桥梁。它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。

总结:在MVVM的框架下视图和模型是不能直接通信的。它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信。MVVM流程图如下: image

vue是如何实现双向数据绑定

vue是采用Object.defineProperty的getter和setter,并结合观察者模式来实现数据绑定的。当把一个普通的javascript对象传给Vue实例来作为它的data选项时,Vue将遍历它的属性,用Object.defineProperty将它们转为getter/setter。用户看不到getter/setter,但是在内部它们让Vue追踪依赖。在属性被访问和修改时通知变化。

Observer 数据监听器,能够对数据对象的所有属性进行监听,如有变动可拿到最新的值并通知订阅者,内部采用Obiect.defineProperty的getter和setter来实现。

Complie指令解析器,它的作用对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定Observer和Complie的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应的回调函数

Watcher订阅者,作为连接Observer和Complie的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数。 Dep消息订阅器,内部维护了一个数组,用来收集订阅者(watcher),数据变动触发notify函数,再调用订阅者的update方法。

从图中可以看出,当执行 new Vue() 时,Vue就是进入了初始化阶段,一方面Vue会遍历data选项中的属性,并且Object.defineProperty将它们转换为getter/setter,实现数据变化监听功能;Vue的指令编译器Compile对元素节点的指令进行扫描和解析,初始化视图,并订阅Wacther来更新视图,此时wather会将自己添加到消息订阅器(Dep),初始化完毕。

当数据发生变化时,Observer中的setter方法被触发,setter会立即调用Dep。Dep开始遍历所有的订阅者,并调用订阅者的update方法,订阅者收到通知后对视图进行相应更新

dashengzi66 commented 3 years ago

什么是Virtual DOM 定义: 就是用一个原生的 JS 对象去描述一个 DOM 节点 好处: 1.将真实元素节点抽象成 VNode,有效减少直接操作 dom 次数,从而提高程序性能 2.方便实现跨平台

dashengzi66 commented 3 years ago

Vue组件之间的传值

父子组件通信

dashengzi66 commented 3 years ago

H5新特性

语义标签 example 增强型表单 视频和音频 Canvas绘图 SVG绘图 地理定位 拖放API WebWorker WebStorage WebSocket

dashengzi66 commented 3 years ago

地址栏输入 URL 敲下回车后发生了什么?

网络上的讲解

URL解析->DNS查询->TCP连接->HTTP请求->响应请求->页面渲染

dashengzi66 commented 3 years ago

Vue封装组件的过程

1.使用Vue.extend()创建一个组件 2.使用Vue.component()方法注册组件 3.如果子组件需要数据,可以在props中接受定义 4.子组件修改好数据之后,想把数据传递给父组件,可以使用emit()方法

dashengzi66 commented 3 years ago

localStorage和vuex的区别

1.存储地方不同 vuex 存储在内存(vuex 属于js,因此vuex使用的数据自然会放在内存),localstorage则以文件的形式存储在本地 localStorage和sessionStorage只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理

2.应用场景不同 vuex用于组件之间的传值(app大部分都是由单页面组件组成),localstorage,sessionstorage则主要用于不同页面之间的传值。

3.永久性:当刷新页面(这里的刷新页面指的是 --> F5刷新,属于清除内存了)时vuex存储的值会丢失,sessionstorage页面关闭后就清除掉了,localstorage不会。