前端面试题整理(一)

一、vue中 computed 的原理

在具体讲computed之前,我们需要先知道几个知识点:

  • Vue.js 的核心包括一套“响应式系统”。
  • Vue 的响应式,核心机制是 观察者模式。
    • 数据是被观察的一方,发生改变时,通知所有的观察者,这样观察者可以做出响应,比如,重新渲染然后更新视图。
  • Dep :每个属性都拥有自己的消息订阅器dep,用于存放所有订阅了该属性的观察者对象。
    • dep 的属性:
      • id :唯一的标识符
      • subs :存放订阅者 watcher 的数组
  • Computed -> 惰性求值的观察者,具有缓存性,当依赖发生变化后,第一次访问 computed 属性,才会计算新的属性,并将该属性挂载到 vm (Vue实例)上

computed原理

原理分析
  • 当组件初始化的时候,computed 和 data 会分别建立各自的响应系统,Observer遍历 data 中每个属性,使用 Object.defineProperty 的 get/set 方法对其进行数据劫持
  • 初始化 computed 会调用 initComputed 函数
    • new 一个 watcher 实例,watcher 中实例化一个 Dep (消息订阅器) 收集依赖
      • data -> Dep -> watcher ,通过dep在data和watcher之间建立了依赖
      • 创建的时候不会触发 get 方法
  • 调用 computed 时会触发其 Object.defineProperty 的 get 访问器函数
    • dirty = true 会调用 watcher.get 方法重新计算,随后 dirty = false
    • 启动依赖收集,调用 watcher.depend() 方法向自身的消息订阅器 dep.subs 中添加订阅者(其他属性的watcher)
  • 当某个属性(依赖项)发生变化,触发 set 拦截函数,然后调用自身消息订阅器dep, dep 通过 notify 遍历当前 dep.subs 通知每个 watcher 更新(watcher.update())。

二、webpack 优化有哪些

减少 Webpack 打包时间
  1. 优化 Loader (原因:Babel 会将代码转为字符串生成 AST,然后对 AST 继续进行转变最后再生成新的代码,项目越大,转换代码越多,效率就越低。)

     优化 Loader 的文件搜索范围
    
	module.exports = {
	  module: {
	    rules: [
	      {
	        // js 文件才使用 babel
	        test: /\.js$/,
	        loader: 'babel-loader',
	        // 只在 src 文件夹下查找
	        include: [resolve('src')],
	        // 不会去查找的路径
	        exclude: /node_modules/
	      }
	    ]
	  }
	}
将 Babel 编译过的文件缓存起来,下次只需要编译更改过的代码文件即可,这样可以大幅度加快打包时间
loader: 'babel-loader?cacheDirectory=true'
  1. HappyPack (Node是单线程,webpack打包也是单线程)

     HappyPack 可以将 Loader 的同步执行转换为并行的,这样就能充分利用系统资源来加快打包效率了
    
  2. 代码压缩
    (举例 js)
    webpack3 :webpack-parallel-uglify-plugin 来并行运行 UglifyJS
    webpack4 :mode 设置为 production 就可以默认开启以上功能

  3. DllPlugin
    DllPlugin 可以将特定的类库提前打包然后引入。
    减少打包类库的次数,只有当类库更新版本才有需要重新打包,并且也实现了将公共代码抽离成单独文件的优化方案。

  4. resolve.alias:通过别名来映射路径,能让 Webpack 更快找到路径

  5. module.noParse:当确定一个文件下没有其他依赖,就可以使用该属性让 Webpack 不扫描该文件,这种方式对于大型的类库很有帮助

  6. externals
    想引用一个库,但是不想让webpack打包,且不影响我们在程序中以CMD、AMD或者window/global全局等方式进行使用,那就可以通过配置externals。

  7. resolve.extensions
    import 时最好写扩展名
    如果你导入的文件没有添加后缀就会按照这个顺序查找文件。我们应该尽可能减少后缀列表长度,然后将出现频率高的后缀排在前面。

减少 Webpack 打包后的文件体积
  1. 懒加载、按需加载
    使用按需加载,将每个路由页面单独打包为一个文件;
    也可以对大型类库使用按需加载
  2. Scope Hoisting
    Scope Hoisting 会分析出模块之间的依赖关系,尽可能的把打包出来的模块合并到一个函数中去。
  3. Tree Shaking
    移除 JavaScript 上下文中的未引用代码(dead-code)
    Webpack 4 :mode 设置为 production 会自动启动这个优化功能。

三、跨域的解决方案

  1. jsonp
    动态创建scipt,再清求一个带参网址实现跨域通信(script 标签的 src 属性不受同源策略的限制 );
    jQuery ajax;
    jsonp缺点:只能实现 get 一种请求。

  2. 跨域资源共享(CORS)
    后端添加允许的请求头

	// 配置 cors 跨域
	header("Access-Control-Allow-Origin:*");
	header("Access-Control-Request-Methods:GET, POST, PUT, DELETE, OPTIONS");
	header('Access-Control-Allow-Headers:x-requested-with,content-type,test-token,test-sessid');
  1. nginx代理
    实现思路:通过Nginx配置一个代理服务器域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域访问。
    nginx具体配置:
	#proxy服务器
	server {
	    listen       81;
	    server_name  www.domain1.com;
	
	    location / {
	        proxy_pass   http://www.domain2.com:8080;  #反向代理
	        proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
	        index  index.html index.htm;
	
	        # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
	        add_header Access-Control-Allow-Origin http://www.domain1.com;  #当前端只跨域不带cookie时,可为*
	        add_header Access-Control-Allow-Credentials true;
	    }
	}
  1. nodejs中间件代理
    node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发
    使用node + express + http-proxy-middleware搭建一个proxy服务器。
  2. WebSocket协议
    WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。
    原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
  3. postMessage跨域
    window属性的postMessage(HTML5 XMLHttpRequest Level 2中的API)
    postMessage(data,origin)
  4. document.domain + iframe跨域
    仅限主域相同,子域不同的跨域应用场景。
    实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
  5. location.hash + iframe
    a欲与b跨域相互通信,通过中间页c来实现。 三个页面,不同域之间利用iframe的location.hash传值,相同域之间直接js访问来通信。
  6. window.name + iframe跨域
    name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

四、React的diff算法,规则是什么?

React Diff 算法的差异查找实质是对两个JavaScript对象(虚拟DOM和真实DOM)的差异查找,所以React更新阶段才会有Diff算法的运用。
规则:

  • Web UI中 DOM 节点跨层级的移动操作特别少,可以忽略不计
  • 拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件将会生成不同的树形结构
  • 对于同一层级的一组子节点,它们可以通过唯一的 id 进行区分

五、为什么不建议在 componentWillMount 做Ajax等操作?

一个组件的 componentWillMount 比 componentDidMount 也早调用不了几微秒,性能没啥提高;而且,等到异步渲染开启的时候,componentWillMount 就可能被中途打断,中断之后渲染又要重做一遍(例如:在 componentWillMount 中做 AJAX 调用,代码里看到只有调用一次,但是实际上可能调用 N 多次,这明显不合适)。相反,若把 AJAX 放在 componentDidMount,因为 componentDidMount 在第二阶段,所以绝对不会多次重复调用,这才是 AJAX 合适的位置。

六、介绍React hooks

hooks是react 16.8引入的特性,他允许你在不写 class 的情况下操作 state 和 react 的其他特性。
hook s只是多了一种写组件的方法,使编写一个组件更简单更方便,同时可以自定义hook把公共的逻辑提取出来,让逻辑在多个组件之间共享。
在编写函数组件并意识到需要向其添加一些state 时,就可以使用hook。

hook的钩子:

  • useState() 保存组件状态
  • useEffect() 处理副作用
  • useContext() 获取context的值,减少组件层级
  • useReducer() 跟 redux 中的数据流的概念非常接近
  • useCallback 记忆函数
  • useRef 表示可以定义一个变量, 在函数体内实现唯一的引用
  • useMemo() 主要用于渲染过程优化,两个参数依次是计算函数(通常是组件函数)和依赖状态列表,当依赖的状态发生改变时,才会触发计算函数的执行。如果没有指定依赖,则每一次渲染过程都会执行该计算函数。

React Hooks 提供为状态管理提供了新的可能性,尽管我们可能需要额外去维护一些内部的状态,但是可以避免通过 renderProps / HOC 等复杂的方式来处理状态管理的问题。Hooks 带来的好处如下:

  • 更细粒度的代码复用,并且不会产生过多的副作用
  • 函数式编程风格,代码更简洁,同时降低了使用和理解门槛
  • 减少组件嵌套层数
  • 组件数据流向更清晰

React Hook

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值