【前端面试笔记】面试准备01

2.对es6有了解么?es6有哪些新特性?可以讲一下promise,generator吗?

答:es6 是5.1版本后的JS的下一代标准。

我知道的有十个新特性,比如:

  • 新增了let,const的变量声明,他们都是块级作用域,作用范围仅限最近的花括号,其中let是定义变量的,const是定义常量的;
  • 模板字符串:使用反引号使多行字符串更加方便,嵌入变量用${}
  • 箭头函数:不需要function,省略return,继承当前上下文this
  • 函数参数默认值:可以写在函数(参数赋值)
  • 二进制0b/0B和八进制0o/0O
  • 对象和数组解构
  • spread、rest操作符
  • 对象超类,允许使用super
  • for……of:遍历迭代数,例如数组;for……in:遍历对象中的属性
  • ES6中的属性
  • 提供了原生的Promise对象

Promise对象:用来处理异步操作,保存着某个未来才会结束的事件,提供了统一的API,各个异步操作都可以用同样的方法进行。特点,1,对象的状态不受外界影响,promise对象代表一个异步操作,有3种状态,pending,进行中;fulfilled,已成功;rejected,已失败,只有异步操作的结果可以决定当前是哪一个状态;2,一旦状态改变不会再变,任何时候都能得到这个结果。pending->fulfilled;pending->rejected;此时称之为resolved已定型;

有了它就可以将异步操作以同步操作的流程表达出来,避免层层嵌套的回调函数;

缺点是,1,无法取消promise,一旦新建就会立即执行,无法中途取消;2,不设置回调函数,promise内部抛出的错误不会反应到外部;3,pending状态时,无法得知进展到哪个状态。、

Promise实例生成后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

Generator函数:ES6提供的一种异步编程解决方案,执行generator函数会返回一个遍历器对象,返回的遍历器对象可以依次遍历generator内部的每个状态。

特征:1.function命令与函数名之间有个* ,2,函数体内部使用yield语句定义不同的内部状态。

Iterator遍历器:Js原本表示集合的数据结构主要是数组和对象,ES6新增了MAP和SET,此时需要一个统一的接口机制来处理所有不同的数据结构,为不同的数据结构提供统一的访问机制。

作用有3个:1,为各种数据提供统一的简便的访问接口,1,使得数据结构的成员能够按某种次序排列,3,主要供for……of遍历命令消费;

遍历过程:1,创建一个指针对象,指向当前数据结构的起始位置;2,调用指针对象的next方法,指向第一个成员。3,不断调用next方法直到指向数据结构的最后位置;

每次调用会返回当前成员的信息,包含value和done两个属性的对象,done是代表遍历是否结束。

3.问如何实现一个文本和一个输入框的两端对齐

答:文本的两端对齐:text-align:justify,text-align-last:justify(针对最后一行设置,但兼容性不好),因为它针对的段落文本,对于最后一行不会两端对齐,所以:一种是在文字后添加一行空<span>标签,另一种是在文本后添加伪类:afer,设置display属性为inline-block,宽度为100% ;

4.如果你想做一个组件给后端使用,你会怎么做?

vue组件化,然后提供给后端想要的效果,注入css

5.前端代码不变的情况下,如何维护组件的健壮性

eg:后端返回了一个新的键值比如以前a只能赋值123,现在给了4怎么办

答:建立个机制自动生成所需的值,回答了将键值对扩充。

6.前端如何处理路由? 

答:我们可以通过记录 url 来记录 ajax 的变化,从而实现前端路由。

将 url 映射到组件,在加上一系列的复杂情况的处理,比如说 hash 模式和 history 模式如何兼容,重定向,别名,嵌套,传参,然后是跳转,路由之间的跳转需要提供各种“钩子”,处理好各种情况就是一个完整的前端路由库了。

前端路由的实现方式主要有两种:

  • hash
  • history

1、hash 即 window.loacation.hash,url 中以“#”为标识符,如:www.xxx/com/list.ht… ,这个值可读可写,读取时,可以用来判断网页状态,写入时会在不重新载入网页的情况下给浏览器增加一条历史记录,有了这种特性就有了前端路由的雏形,因为改变#之后的内容相当于改变了 url,但是并没有重新向服务器发送请求。JavaScript 可以通过 window.onhashchange 来监听 url 变化,以实现不同组件的切换。

目前主要的路由库有 vue-router,react-router,他们的主要功能是存储路由的 hash 以及对应的函数,然后监听 hash 的变化执行对应的函数。以 vue-router 为例,看一下他的监听源码:

setupListeners () {  //设置监听器
  const router = this.router
  const expectScroll = router.options.scrollBehavior
  const supportsScroll = supportsPushState && expectScroll

  if (supportsScroll) {
    setupScroll()
  }

  window.addEventListener(supportsPushState ? 'popstate' : 'hashchange', () => {
    const current = this.current
    if (!ensureSlash()) {
      return
    }
    this.transitionTo(getHash(), route => {
      if (supportsScroll) {
        handleScroll(this.router, route, current, true)
      }
      if (!supportsPushState) {   // hash变化改变view
        replaceHash(route.fullPath)
      }
    })
  })
}

2,由于 html5 的发布,引入了 history.pushState()history.replaceState() 方法,它们分别可以添加和修改历史记录条目。pushState 需要三个参数,一个状态对象(可以通过 onpopstate 事件获取到),一个标题 (目前被忽略)和一个 URL,replaceState 参数也是一样。通常与 window.onpopstate 配合使用,这个为前端路由的另一种模式奠定了基础,但是这种方式的 url 是一个完整的如http://www.xxx.com/list/complete,他每一次改变都会向服务发送一次请求资源(其实我们是没有这个页面地址的),所以需要服务器端增加一条配置,如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是我们的主页面。
作者:梁仔
链接:https://juejin.im/post/5c0a0bd6e51d451dc066fd33
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

7.vue-router有哪些方式,有什么区别?

答:有两种模式 hash 和 history

前端路由的核心,就在于 —— 改变视图的同时不会向后端发出请求

为了达到这一目的,浏览器当前提供了以下两种支持:

  1. hash —— 即地址栏 URL 中的 # 符号(此 hash 不是密码学里的散列运算)。
    比如这个 URL:http://www.abc.com/#/hello,hash 的值为 #/hello。它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
  2. history —— 利用了 HTML5 History Interface 中新增的 pushState()replaceState() 方法。(需要特定浏览器支持)
    这两个方法应用于浏览器的历史记录栈,在当前已有的 backforwardgo 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。

因此可以说,hash 模式和 history 模式都属于浏览器自身的特性,Vue-Router 只是利用了这两个特性(通过调用浏览器提供的接口)来实现前端路由。

使用场景

一般场景下,hash 和 history 都可以,除非你更在意颜值,# 符号夹杂在 URL 里看起来确实有些不太美丽。

如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成
URL 跳转而无须重新加载页面。—— Vue-router 官网

另外,根据 Mozilla Develop Network 的介绍,调用 history.pushState() 相比于直接修改 hash,存在以下优势:

  • pushState() 设置的新 URL 可以是与当前 URL 同源的任意 URL;而 hash 只可修改 # 后面的部分,因此只能设置与当前 URL 同文档的 URL;
  • pushState() 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中;而 hash 设置的新值必须与原来不一样才会触发动作将记录添加到栈中;
  • pushState() 通过 stateObject 参数可以添加任意类型的数据到记录中;而 hash 只可添加短字符串;
  • pushState() 可额外设置 title 属性供后续使用。

当然啦,history 也不是样样都好。SPA 虽然在浏览器里游刃有余,但真要通过 URL 向后端发起 HTTP 请求时,两者的差异就来了。尤其在用户手动输入 URL 后回车,或者刷新(重启)浏览器的时候。

  1. hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.abc.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
  2. history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.abc.com/book/id。如果后端缺少对 /book/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”

小结

结合自身例子,对于一般的 Vue + Vue-Router + Webpack + XXX 形式的 Web 开发场景,用 history 模式即可,只需在后端(Apache 或 Nginx)进行简单的路由配置,同时搭配前端路由的 404 页面支持。
作者:旭1478080873000
链接:https://juejin.im/post/5a61908c6fb9a01c9064f20a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

8.如果对方复制了你一个网址给另一个人,怎样保存这个路由?

9.如何保存路由信息呢,比如刷新?

<keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。

<keep-alive>
    <router-view>
        <!-- 所有路径匹配到的视图组件都会被缓存! -->
    </router-view>
</keep-alive>

如果只想 router-view 里面某个组件被缓存,怎么办?

  • 使用 include/exclude
  • 增加 router.meta 属性

使用 include/exclude

// 组件 a
export default {
  name: 'a',
  data () {
    return {}
  }
}
<keep-alive include="a">
    <router-view>
        <!-- 只有路径匹配到的视图 a 组件会被缓存! -->
    </router-view>
</keep-alive>

exclude 例子类似。

缺点:需要知道组件的 name,项目复杂的时候不是很好的选择

增加 router.meta 属性

// routes 配置
export default [
  {
    path: '/',
    name: 'home',
    component: Home,
    meta: {
      keepAlive: true // 需要被缓存
    }
  }, {
    path: '/:id',
    name: 'edit',
    component: Edit,
    meta: {
      keepAlive: false // 不需要被缓存
    }
  }
]
<keep-alive>
    <router-view v-if="$route.meta.keepAlive">
        <!-- 这里是会被缓存的视图组件,比如 Home! -->
    </router-view>
</keep-alive>

<router-view v-if="!$route.meta.keepAlive">
    <!-- 这里是不被缓存的视图组件,比如 Edit! -->
</router-view>

优点:不需要例举出需要被缓存组件名称

【加盐】使用 router.meta 拓展

假设这里有 3 个路由: A、B、C。

  • 需求:

    • 默认显示 A
    • B 跳到 A,A 不刷新
    • C 跳到 A,A 刷新
  • 实现方式

    • 在 A 路由里面设置 meta 属性:
{
        path: '/',
        name: 'A',
        component: A,
        meta: {
            keepAlive: true // 需要被缓存
        }
}
  • 在 B 组件里面设置 beforeRouteLeave
export default {
        data() {
            return {};
        },
        methods: {},
        beforeRouteLeave(to, from, next) {
             // 设置下一个路由的 meta
            to.meta.keepAlive = true;  // 让 A 缓存,即不刷新
            next();
        }
};
  • 在 C 组件里面设置 beforeRouteLeave
export default {
        data() {
            return {};
        },
        methods: {},
        beforeRouteLeave(to, from, next) {
            // 设置下一个路由的 meta
            to.meta.keepAlive = false; // 让 A 不缓存,即刷新
            next();
        }
};

这样便能实现 B 回到 A,A 不刷新;而 C 回到 A 则刷新。
作者:RoamIn
链接:https://www.jianshu.com/p/0b0222954483
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

10.我看你简历对代码规范有了解,有什么规范是你觉得很重要的?

11.react和vue有什么区别

监听数据变化的实现原理不同

  • Vue 通过 getter/setter 以及一些函数的劫持,能精确知道数据变化,不需要特别的优化就能达到很好的性能

  • React 默认是通过比较引用的方式进行的,如果不优化(PureComponent/shouldComponentUpdate)可能导致大量不必要的VDOM的重新渲染

为什么 React 不精确监听数据变化呢?这是因为 Vue 和 React 设计理念上的区别,Vue 使用的是可变数据,而React更强调数据的不可变。所以应该说没有好坏之分,Vue更加简单,而React构建大型应用的时候更加鲁棒。

数据流的不同

现在我们只有 组件 <--> DOM 之间的双向绑定这一种。

然而 React 从诞生之初就不支持双向绑定,React一直提倡的是单向数据流,他称之为 onChange/setState()模式。

不过由于我们一般都会用 Vuex 以及 Redux 等单向数据流的状态管理框架,因此很多时候我们感受不到这一点的区别了。

HoC 和 mixins

在 Vue 中我们组合不同功能的方式是通过 mixin,而在React中我们通过 HoC (高阶组件)。

React 最早也是使用 mixins 的,不过后来他们觉得这种方式对组件侵入太强会导致很多问题,就弃用了 mixinx 转而使用 HoC,关于mixin究竟哪里不好,可以参考React官方的这篇文章 Mixins Considered Harmful

而 Vue 一直是使用 mixin 来实现的。

为什么 Vue 不采用 HoC 的方式来实现呢?

高阶组件本质就是高阶函数,React 的组件是一个纯粹的函数,所以高阶函数对React来说非常简单。

但是Vue就不行了,Vue中组件是一个被包装的函数,并不简单的就是我们定义组件的时候传入的对象或者函数。比如我们定义的模板怎么被编译的?比如声明的props怎么接收到的?这些都是vue创建组件实例的时候隐式干的事。由于vue默默帮我们做了这么多事,所以我们自己如果直接把组件的声明包装一下,返回一个高阶组件,那么这个被包装的组件就无法正常工作了。

推荐一篇很棒的文章讲的是vue中如何实现高阶组件 探索Vue高阶组件

组件通信的区别

其实这部分两个比较相似。在Vue 中有三种方式可以实现组件通信:

  • 父组件通过 props 向子组件传递数据或者回调,虽然可以传递回调,但是我们一般只传数据,而通过事件的机制来处理子组件向父组件的通信

  • 子组件通过 事件 向父组件发送消息

  • 通过 V2.2.0 中新增的 provide/inject 来实现父组件向子组件注入数据,可以跨越多个层级。

另外有一些比如访问 $parent/$children等比较dirty的方式这里就不讲了。

在 React 中,也有对应的三种方式:

  • 父组件通过 props 可以向子组件传递数据或者回调

  • 可以通过 context 进行跨层级的通信,这其实和 provide/inject 起到的作用差不多。

可以看到,React 本身并不支持自定义事件,Vue中子组件向父组件传递消息有两种方式:事件和回调函数,而且Vue更倾向于使用事件。但是在 React 中我们都是使用回调函数的,这可能是他们二者最大的区别。

模板渲染方式的不同

在表层上, 模板的语法不同

  • React 是通过JSX渲染模板

  • 而Vue是通过一种拓展的HTML语法进行渲染

但其实这只是表面现象,毕竟React并不必须依赖JSX。
在深层上,模板的原理不同,这才是他们的本质区别:

  • React是在组件JS代码中,通过原生JS实现模板中的常见语法,比如插值,条件,循环等,都是通过JS语法实现的

  • Vue是在和组件JS代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要 v-if 来实现

对这一点,我个人比较喜欢React的做法,因为他更加纯粹更加原生,而Vue的做法显得有些独特,会把HTML弄得很乱。举个例子,说明React的好处:

react中render函数是支持闭包特性的,所以我们import的组件在render中可以直接调用。但是在Vue中,由于模板中使用的数据都必须挂在 this 上进行一次中转,所以我们import 一个组件完了之后,还需要在 components 中再声明下,这样显然是很奇怪但又不得不这样的做法。

Vuex 和 Redux 的区别

从表面上来说,store 注入和使用方式有一些区别。

在 Vuex 中,$store 被直接注入到了组件实例中,因此可以比较灵活的使用:

  • 使用 dispatch 和 commit 提交更新

  • 通过 mapState 或者直接通过 this.$store 来读取数据

在 Redux 中,我们每一个组件都需要显示的用 connect 把需要的 props 和 dispatch 连接起来。

另外 Vuex 更加灵活一些,组件中既可以 dispatch action 也可以 commit updates,而 Redux 中只能进行 dispatch,并不能直接调用 reducer 进行修改。

从实现原理上来说,最大的区别是两点:

  • Redux 使用的是不可变数据,而Vuex的数据是可变的。Redux每次都是用新的state替换旧的state,而Vuex是直接修改

  • Redux 在检测数据变化的时候,是通过 diff 的方式比较差异的,而Vuex其实和Vue的原理一样,是通过 getter/setter来比较的(如果看Vuex源码会知道,其实他内部直接创建一个Vue实例用来跟踪数据变化)

而这两点的区别,其实也是因为 React 和 Vue的设计理念上的区别。React更偏向于构建稳定大型的应用,非常的科班化。相比之下,Vue更偏向于简单迅速的解决问题,更灵活,不那么严格遵循条条框框。因此也会给人一种大型项目用React,小型项目用 Vue 的感觉。
作者:binbinsilk
链接:https://juejin.im/post/5b8b56e3f265da434c1f5f76
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

12.你还有什么想问的?

前端现在在阿里的体系架构是什么,react

如何提升自己呢?

猜你喜欢

转载自blog.csdn.net/weixin_41835977/article/details/88739568
今日推荐