FrankKai / FrankKai.github.io

FE blog
https://frankkai.github.io/
363 stars 39 forks source link

一些特别棒的面试题[0] #3

Open FrankKai opened 6 years ago

FrankKai commented 6 years ago

RT

FrankKai commented 6 years ago

1.说一下你熟悉的设计模式 我最熟悉的设计模式:工厂模式(ES5),组件设计模式(ES6) 工厂模式(ES5,基于prototype。此例中基类Base,子类Factory)

var Factory = function () {
    if(!(this instanceof Factory)){
        return new Factory();
    }
}
Factory.prototype = Object.assign(new Base(), {
    version: '0.0.1',
    defaultOption:{
        title:'标题'
    },
    init:function (cfg) {
        this.title = cfg.title || '';
        this.currentOption = Object.assign(this.defaultOption,{
           //...
        })
    },
    render: function () {
        var option = this.currentOption;
        this.chart.setOption(option);
    },
    showTitle: function () {
        this._showTitle();
    }
})

组件设计模式(ES6,基于class,方便继承和初始化,也是React组件的推荐写法,我比较喜欢。此例中父类Compnent,子类Retrive)

class Retrive extends Component {
    constructor (props) {
        super(props);
        this.state = {
            name:''
        };
        this.getRemoteData = this.getRemoteData.bind(this);
    }
    getRemoteData (data) {
        this.state.retriveResult = data;
    }
    render(){
        return (
            <div className="Retrive">
                <Button name="search" onClick={this.getRemoteData}>查询</Button>
            </div>
        );
    }
}
FrankKai commented 6 years ago

2.说一下你理解的模块机制 AMD: 异步模块加载规范。 a.js,定义一个依赖jQuery和echrts的组件。

define(['jquery', 'echarts'], function ($, echarts) {
  var AMD = function(){}
  AMD.prototype = {
       title:'',
        foo: function(){}//AMD类或者继承AMD类的子类的属性
  }
  function bar(){}//返回,公共属性
   function baz(){} //未返回,私有属性
  return {
       main:AMD,
       bar: bar
  }
});

如果b.js依赖a.js,可以这样

define(['./a'], function (a) {
     //调用构造函数,foo
     var instance_amd = new a.main();
     instance_amd.foo()
      //调用bar
     a.bar()
});

ES6 modules: 和python的包机制很类似,导入import,导出export。

1.场景:vue,react推荐机制,需要babel转义成es5以兼容浏览器。 2.关于import...(from...) ①.import...from...的from命令后面可以跟很多路径格式,若只给出vue,axios这样的包名,则会自动到node_modules中加载;若给出相对路径及文件前缀,则到指定位置寻找。 ②.可以加载各种各样的文件:.js、.vue、.less等等。 ③.可以省略掉from直接引入。 3.关于export ①.导出的可以是对象,表达式,函数,类 ②.导出是为了让别人导入 4.言外话:使用es6的话,有一个特别好的规范去遵守,airbnb的es6规范(https://github.com/airbnb/javascript

CommonJS:nodejs中使用较多,关键词是require,没写过node包,只引用过别人的模块,所以内部实现原理不是很清楚。

FrankKai commented 6 years ago

3.MVVM原理

MVVM是一种软件架构模式,MVVM有助于前后端分离。 View:视图层,粗略理解为DOM。 Model:与数据库对应的model,一般为json格式,作为req的body通过http(s)与数据库实现通信。 ViewModel:View与Model通过ViewModel实现双向绑定。

核心是提供对View和ViewModel的双向数据绑定,这样使得ViewModel的改变View立即变化,MVVM在前端的实现有:angular,vue,react。

vue中的常用数据双向绑定。

view:{{message}}
viewModel v-model="message"
model:message
<div id="app-6">
  <p>{{ message }}</p>
  <input v-model="message">
</div>

var app6 = new Vue({
  el: '#app-6',
  data: {
         message: 'Hello Vue!'
  }
})

单文件组件中的话,就多了一个用html5的template标签将view和viewModel包裹起来,model部分停留在script标签部分。

<template>
     view
     viewModel
</tamplate>
<script>
     model
</script>
<styles>
     为了让view好看点
</styles>

react的话,我在使用的过程中,没有听说过双向绑定的东西,对redux reducers推荐写为纯函数印象深刻,纯函数的话,感觉应该有点单项数据流的意思。

既然说到框架了,说一个最让我感觉有趣的点,那就是组件间的通信,对于简单组件,只涉及父子级别的通信的,vue使用on emit的方式,react使用props。对于复杂级别通信,爷爷父亲儿子孙子等等时,vue推荐使用vuex,react推荐使用redux,统一的全局状态树用来做状态管理非常好,可以使得逻辑非常清晰。vue项目文件结构研究不深,react的项目文件结构的话,presentational和containers的设计方法感觉非常有道理,一个负责视图一个负责数据,非常清爽。

FrankKai commented 6 years ago

4.最熟悉的框架路由机制 vue路由依赖:vue-router 通过组合组件来组成单页应用程序,只需要将组件映射到路由即可。 前端路由的核心,就在于 —— 改变视图的同时不会向后端发出请求。 需要注意2种模式的区别:hash模式和history模式,hash模式会在后面加一个很丑的#,可以开启history去掉。 hash模式原理:它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。hash可以理解为锚点,例如./index.html/#/foo,hash值为#/foo,这样不会跳转页面。就相当于统一页面的不同锚点,页面间跳转与 ./index.html/#foo到./index.html/#bar类似。

./store/index.js

import Router from 'vue-router'
Vue.use(Router)
export default new Router({
  routes: [
  {
  path: '/common',
  name: 'common',
  component: Common
  }
]

路由层面还会包括嵌套路由,动态路由以及重定向,相当于自己模仿浏览器请求然后服务器响应模式,其实不涉及向后端请求,仅在浏览器就可以实现页面跳转,前段时间我做的用户权限控制就用到了vue-router,相比MVC结构下的后端路由,清晰了不少,这样后端只要负责路由编写api就好。

FrankKai commented 6 years ago

5.状态管理 下面是我在用vuex做项目时的一些思考,简单修改了一下,也添加了一些关于redux的思考。

vuex state,前端data view,前端DOM actions,用户操作,引起data变化从而导致DOM变化。

多个组件(视图)共享状态:通俗来讲,就是多个组件间会通信时,导致从后端拿来的数据发生变化,当组件较多时,如果兄弟组件间的通信都依赖父组件进行通信,会导致组件间的耦合非常高,从而导致项目逻辑混乱,难以维护。

多个组件(视图)依赖于同一状态。 来自不同视图的行为需要变更同一状态。

全局单例模式管理,把组件的共享状态抽取出来 不管在组件树的哪个位置,任何组件都能获取状态或者触发行为!

实践出真知: 1.state存放在index.js中,创建的Store实例getter,mutations,actions等,可以分离出来 2.getters存放在getter.js中,数据流为state→getter→组件,getter相当于一个数据获取过滤器,从仓库拿特定数据到组件,相当于对computed的集中处理。 3.mutations存放在mutations.js中,数据流为组件→mutations→state,mutations相当于一个数据提交发射器,从组件提交数据到仓库 4.actions存放在actions.js中,数据流为组件→actions→mutations→state,异步操作的主要场所。 5.modules是开发大型应用时需要用到的,每个module都有单独的states,getters,actions以及mutation,有一股nodejs模块的味道。

vuex三原则: 1.唯一数据源 2.保持状态只读 3.数据改变只能通过纯函数完成 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

!!!mutation和action的区别!!!

mutation只变更本地的状态,也就是说,直接只去修改store中的数据。 action包含异步操作,直接调用api,通过api的数据,再提交mutation。

可以说,action只比mutation多了一个异步调用api的操作,因为调用api后,一般有2种返回结果,succes或者error,或者是promise的多种状态,根据不同的。

最近在学习redux,组件dispatch一个action到store,相当于发送一个http请求,然后store做出响应,返回一个response给组件。和vuex大致类似,唯一有区别的是,vuex还需要引入react-redux,引入Provider和connect连接组件和store。

FrankKai commented 6 years ago

6.统计字符串中单词出现次数 " hi how are you i am fine thank you youtube am am ",统计"you"出现的次数。

function wordCount(str,word){
  var str = str || "";
  var word = word || "";
  var strArr = str.split(" ");
  var count = 0;
  for(var i=0;i<strArr.length;i++){
      if(word===strArr[i]){
          count++
      }
  }
  return count;
}
wordCount("hi how are you i am fine thank you youtube am am","you");

如果字符串没有空格怎么办?

function wordCount(str,word){
  var str = str || "";
  var word = word || "";
  var count = 0;
  var index = str.indexOf(word);
  while(index!==-1){
      count++;
      str = str.substr(index+word.length);
      index = str.indexOf(word)
  }
  return count;
}
wordCount("hihowareyouiamfinethankyouyoutubeamam","you");

如果不用js内置字符串函数,自己用每个字符对比呢?

function wordCount(str,word){
  var num = 0;
  var str = str+"  " || "";
  var word = word || "";
  var strArr = str.split("");
  var wordArr = word.split("");
  var count = 0;
  function compare(arr1,a,arr2,b){
        if(b+a<arr2.length){
          if(arr1[a]===arr2[b+a]){
            num++;
            return compare(arr1,a+1,arr2,b+1)
          }
          if(num===arr1.length){
            count++
            num = 0;
          }
        }
  }
  for(var i=0;i<strArr.length;i++){
      for(var j=0;j<wordArr.length;j++){
        if(wordArr[wordArr.length-1]===strArr[i+wordArr.length-1]){
          compare(wordArr,0,strArr,i+0)
        }
      }
  }
  return count;
}
wordCount("hihowareyouiamfinethankyouyoutubeamam","am");

可以更加高效一些吗?

function wordCount (str,word) {

  var str = str+"  " || "";
  var word = word || "";
  var strArr = str.split("");
  var wordArr = word.split("");
  var wordArrLen = wordArr.length;
  var count = 0;
  var num = 0;

  function compare (arr1,a,arr2,b) {
        if(b+a<arr2.length){
          if(arr1[a]===arr2[b+a]){
            num++;
            return compare(arr1,a+1,arr2,b+1)
          }
          if(num===arr1.length){
            count++;
            num = 0;
          }
        }
  }

  var j = 0;
  while(j<wordArrLen){
      var i = 0;
      while(i<strArr.length){
          if(wordArr[wordArrLen -1]===strArr[i+wordArrLen -1]){
            compare(wordArr,0,strArr,i+0);
          }
          i++;
      }
      j++;
  }
  return count;
}

wordCount("hihowareyouiamfinethankyouyoutubeamam","a");

//1.调整最高层级遍历数组,从37的2次方降到3的2次方,从1369降到9
//2.合并控制变量和控制条件,使用while替代for,去除JS引擎查询i,j是否存在的消耗,会稍微降低代码可读性
//3.对重复引用的wordArr.length,赋值给局部变量wordArrLen,在这里,Array.prototype.length的查询次数从3次降低到1次
zimplexing commented 6 years ago

统计字符串中单词出现次数 用 ' hi how are you i am fine thank you youtube am am '.match(/you/g)岂不是更直接点

FrankKai commented 6 years ago

@zimplexing 这个方式不错,那如何用正则区分you和youtube呢?

zhouchao941105 commented 6 years ago

看到这个题目也写了一下,我把题目理解成youtube里的you也要被搜索到,作者提到的减少计算次数那一块学习到了。

function count(str) {
    let strArr = str.split(' ');
    return strArr.filter(item=>item.includes('you')).length;
}

var countStrWithoutSpace=(function(){
    var countx = 0
    return function re(str) {
        let idx = str.indexOf('you')
        if (idx !== -1) {
            countx++
            str = str.slice(idx + 3)
            return re(str)
        } else {
            return countx
        }
    }
})() 
zimplexing commented 6 years ago

@FrankKai 加一个单词边界判断 ' hi how are you i am fine thank you youtube am am '.match(/\b(?=you)\w{3}\b/g) 这样就区分了youyoutube

WhiteYin commented 6 years ago

' hi how are you i am fine thank you youtube am am '.match(/\syou\s/g); 这样就能匹配单词了。 ' hihowareyouiamfinethankyouyoutubeamam '.match(/you/g); 这样就不用\s来匹配前后空格。

ChenMaoForever commented 6 years ago

' hi how are you i am fine thank you youtube am am '.split('you').length-1

FrankKai commented 6 years ago

@ChenMaoForever ' hi how are you i am fine thank youtube you youtube am am '.split('you').length-1 返回you的数目是4 😅

FrankKai commented 3 years ago

2020年12月28日更新:新题解 " hi how are you i am fine thank you youtube am am ",统计"you"出现的次数。

function countWord(str, target){
    const words = str.split(" ");
    let count = 0;
    for(const word of words){
        if(target === word){
            count++;
        }
    }
    return count;
}
kittors commented 2 years ago

学习到了,感谢