AUI素材网

AUI素材网 查看完整档案

北京编辑中国地质大学(北京)  |  视觉设计 编辑中搜  |  web前端 编辑 www.a-ui.cn/ 编辑
编辑

fererer

个人动态

AUI素材网 提出了问题 · 2019-11-18

大咖们 html5怎么样适配安卓刘海屏?

大神们 html5怎么样适配安卓刘海屏?

关注 4 回答 2

AUI素材网 提出了问题 · 2019-10-31

vue 左侧菜单出现重复菜单问题怎么解决? 有遇到过这样的问题吗?

image
image.png

默认第一次登录进来 左侧菜单显示正常,退出 重新登录 菜单就会重复,退一次登录一次 菜单就加载一次
import { asyncRoutes, constantRoutes } from '@/router'
import { getModules } from '@/api/admin'

import Layout from '@/layout'
/**

  • Use meta.role to determine if the current user has permission
  • @param roles
  • @param route

*/
function hasPermission(roles, route) {
if (route.meta && route.meta.roles) {

return roles.some(role => route.meta.roles.includes(role))

} else {

return true

}
}

///////

export function generaMenu(routes, data) {
let agencyArr = [

{
  path: 'agency/addAgency',
  name: 'addAgency',
  component: () => import('@/views/agency/addAgency'),
  meta: { title: '添加机构' },
  module_name: '添加机构',
  hidden: true
},
{
  path: 'agency/editAgency',
  name: 'editAgency',
  component: () => import('@/views/agency/editAgency'),
  meta: { title: '编辑机构' },
  module_name: '编辑机构',
  hidden: true
},
{
  path: 'agency/operatorList',
  name: 'operatorList',
  component: () => import('@/views/agency/operatorList'),
  meta: { title: '操作员', icon: 'tree' },
  module_name: '操作员',
  hidden: true
},
{
  path: 'agency/salesmanList',
  name: 'salesmanList',
  component: () => import('@/views/agency/salesmanList'),
  meta: { title: '业务员', icon: 'tree' },
  module_name: '业务员',
  hidden: true
}

]
let financialArr = [

{
  path: 'financial/developOrgin',
  name: 'developOrgin',
  component: () => import('@/views/financial/developOrgin'),
  meta: { title: '直接发展机构', icon: 'tree' },
  module_name: '直接发展机构',
  hidden: true
},
{
  path: 'financial/developShop',
  name: 'developShop',
  component: () => import('@/views/financial/developShop'),
  meta: { title: '直接发展商家', icon: 'tree' },
  module_name: '直接发展商家',
  hidden: true
}

]
let businessArr = [

{
  path: 'business/addBusiness',
  name: 'addBusiness',
  component: () => import('@/views/business/addBusiness'),
  meta: { title: '添加商家', icon: 'tree' },
  module_name: '添加商家',
  hidden: true
},
{
  path: 'business/editBusiness',
  name: 'editBusiness',
  component: () => import('@/views/business/editBusiness'),
  meta: { title: '编辑商家', icon: 'tree' },
  module_name: '编辑商家',
  hidden: true
}

]
data.forEach(item => {

// alert(JSON.stringify(item))
if (item.name == 'agency') {
  item.child = item.child.concat(agencyArr)
}
if (item.name == 'financial') {
  item.child = item.child.concat(financialArr)
}
if (item.name == 'business') {
  item.child = item.child.concat(businessArr)
}
const menu = {
  path: item.path == '#' ? '/' + item.name : item.name,
  component:
    item.path == '#' ? Layout : () => import(`@/views/${item.path}`),
  children: [],
  name: item.name,
  meta: {
    title: item.module_name,
    id: item.id
  },
  hidden: item.hidden
}

if (item.child) {
  generaMenu(menu.children, item.child)
}
routes.push(menu)

})
}

///////

/**

  • Filter asynchronous routing tables by recursion
  • @param routes asyncRoutes
  • @param roles

*/
export function filterAsyncRoutes(routes, roles) {
const res = []

routes.forEach(route => {

const tmp = { ...route }
if (hasPermission(roles, tmp)) {
  if (tmp.children) {
    tmp.children = filterAsyncRoutes(tmp.children, roles)
  }
  res.push(tmp)
}

})

return res
}

const state = {
routes: [],
addRoutes: []
}

const mutations = {
SET_ROUTES: (state, routes) => {

state.addRoutes = routes
state.routes = constantRoutes.concat(routes)

}
}

// const actions = {
// generateRoutes({ commit }, roles) {
// return new Promise(resolve => {
// let accessedRoutes
// // if (roles.includes('admin')) {
// // accessedRoutes = asyncRoutes || []
// // } else {
// // accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
// // }
// accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)

// commit('SET_ROUTES', accessedRoutes)
// resolve(accessedRoutes)
// })
// }
// }

//////
const actions = {
generateRoutes({ commit }, roles) {

return new Promise(resolve => {
  let loadMenuData = []
  // 先查询后台并返回左侧菜单数据并把数据添加到路由
  getModules({ role_id: localStorage.getItem('role_id') })
    .then(response => {
      let data = response
      if (response.status !== 200) {
        // this.$message({
        //     message: '菜单数据加载异常',
        //     type: 0
        // })
        console.log('error')
      } else {
        data = response.data
        Object.assign(loadMenuData, data)
        console.log()
        console.log(asyncRoutes)
        generaMenu(asyncRoutes, loadMenuData)
        let accessedRoutes
        // if (roles.includes('admin')) {
        //     // alert(JSON.stringify(asyncRoutes))
        //     accessedRoutes = asyncRoutes || []
        // } else {
        //     accessedRoutes = filterAsyncRoutes(
        //         asyncRoutes,
        //         roles
        //     )
        // }

        if (roles.includes('orgin')) {
          accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
        }

        commit('SET_ROUTES', accessedRoutes)
        resolve(accessedRoutes)
      }
      // generaMenu(asyncRoutes, data)
    })
    .catch(error => {
      console.log(error)
    })
})

}
}

//////
export default {
namespaced: true,
state,
mutations,
actions
}

==========
<script>
export default {
name: "MenuItem",
functional: true,
props: {

icon: {
  type: String,
  default: ""
},
title: {
  type: String,
  default: ""
}

},

render(h, context) {

const { icon, title } = context.props;
const vnodes = [];

if (icon) {
  // console.log(icon);
  // vnodes.push(<svg-icon icon-class={icon}/>)
  vnodes.push(<i class={"iconStyle iconfont " + icon} />);
}

if (title) {
  vnodes.push(
    <span class="left-mar" slot="title">
      {title}
    </span>
  );
}
return vnodes;

}
};
</script>
<style>
.iconStyle {
font-size: 17px !important;
color: rgb(191, 203, 217) !important;
}
.left-mar {
margin-left: 10px;
}
.hideSidebar .left-mar {
margin-left: 0;
}

.menuitem .iconStyle {
color: rgb(31, 107, 194) !important;
}
</style>

关注 3 回答 2

AUI素材网 赞了文章 · 2019-04-24

JavaScript 程序员可以从C++中学到什么

作者:Bret Cameron
翻译:疯狂的技术宅
原文:https://medium.com/@bretcamer...

本文首发微信公众号:前端先锋
欢迎关注,每天都给你推送新鲜的前端技术文章


如何通过了解类型、内存以及低级语言使你成为更好的程序员

clipboard.png

时间的结束?图片来自 Jens Kreuter,由Bret Cameron修改。

像许多开发新手一样,JavaScript 是我学的第一门语言。它是一种 Web 前端编程语言 —— 感谢Node.js —— 它同时也是一种流行的后端工具。

我也相信,作为一种“更高级”的语言,JavaScript 是初学者的绝佳选择。你可以在任何 Web 浏览器上运行它,并且由于具有原型继承和动态类型等功能,学习者在编写和执行第一段代码之前克服的障碍更少。

但是 JavaScript 让初学者更容易上手的因素也让它难以被掌握。它能以看上去不直观的方式运行,并且当涉及到更多不透明的功能时,许多程序员更依赖于试错法,例如隐式类型强制转换或 this 关键字。 知道这些功能比理解它们要容易得多。

clipboard.png

“Any fool can know. The point is to understand.” —— Albert Einstein

因此要成为更高级的 JavaScript 开发人员,试着更深入地了解幕后发生的事情是有很大帮助的。归根结底,最精彩的地方是 V8 JavaScript 引擎:它是使用最广泛的 JavaScript 编译器(Google Chrome、Node.js等的基础之一),它是开源的,因此你可以准确地看到 JavaScript 是怎样在 C ++ 中执行的。

但是本文不是 V8 的指南。相反,它是有关像 C++ 这样的低级语言如何帮助我们提高对 JavaScript 等高级语言的理解的一篇文章。 C++ 不仅可以帮助我们理解底层的编译器代码,而且通过研究 C++ 程序员必须要做而 JavaScript 程序员不必做的事,可以更好地了解在 JavaScript 中提升效率的地方,以及为什么有时会引发问题。

特别是我们将会研究 C++ 中的数据类型和内存管理,以及这些知识如何帮助我们避免类型错误,并防止 JavaScript 中的内存泄漏。还会研究内存管理与时间溢出之间的关系。

JavaScript 中强制类型

在进入 C++ 之前,先让我们看看 JavaScript 是如何处理数据类型以及“类型强制”系统的一些陷阱的。

JavaScript 使用类型强制转化自动将一种数据类型转换为另外一种:字符串转为数字、数字转为字符串、数字或字符串转为布尔值等等。换句话说,如果你没有明确指定所需的类型,JavaScript 将根据一组规则进行猜测。有时这很管用,它可以帮助我们快速简洁地编写代码。但有时候可能是引发混乱的原因。

实际上即使这种行为从根本上来讲是可预测的,但某些自动推测也不那么直观,并且在很多大型项目的代码库中,很容易看到类型强制转换导致了意外错误的发生。例如以下是使用组合字符串和数字的进行运算的一些演示:

"10" - 4
// 6

"10" + 4
// "104"

"20" - "5"
// 15

"20" + "5"
// 205

"20" + + "5"
// 205

"foo" + "bar"
// "foobar"

"foo" + + "bar"
// "fooNaN"

"6" - 3 + 3
// 6

"6" + 3 - 3
// 60

在这些例子中, + 运算符造成了大量的混乱,它可以强制把字符串转为数字,也可以作为连接运算符组合两个或多个字符串。

最后一个例子可能是最令人困惑的。在 "6" + 3 — 3 中,如果首先处理 3 — 3 ,然后再进行字符串连接,"6" + 0 会返回一个字符串,但是在这里返回的结果居然是一个数字!

虽然类型强制转换可以帮助开发人员更快速、简洁地编写代码,但是它使初学者思考得更少,从而也就不清楚为什么这样的转换系统可能会导致错误,特别是在更大、更复杂的代码库中。上面的结果对于经验丰富的 JavaScript 程序来说可能是完全合理的,但它们并不直观!

考虑到 JavaScript 类型强制系统的优点和缺点,现在让我们看看 C++ 是如何处理数据类型的。

C++ 中的类型和内存管理

C++ 之类的低级语言没有这种潜在缺陷,因为必须在定义时声明数据类型。虽然 JavaScript 也有三个关键字  varletconst  用于声明新变量,但在C ++中每个数据类型都有自己的关键字。

例如 C++ 中的 7 种基本数据类型是整型、浮点型、双精度浮点型,字符型,宽字符型,布尔型和无类型。用于定义它们的关键字分别是 intfloatdoubleboolcharwchar_tvoid

下面的代码段包含了每种类型的示例声明,并添加了注释:

#include <iostream>
#include <string>
using namespace std;

int main()
{
 
  // BOOLEANS
  bool isChecked = true;
  
  // INTEGERS
  int age = 24;

  // FLOATS
  // In general, a float has 7 decimal digits of precision, while a double has 15
  float pi7 = 3.1415926;
  double pi15 = 3.141592653589793;
  
  // CHARACTERS
  // Regular characters can contain only values stored in the ISO Latin tables
  // Wide characters, however, can contain unicode values
  char englishGreeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
  wchar_t mandarinGreeting[7] = { 'n', 'ǐ', ' ', 'h', 'ǎ', 'o', '\0' };
  
  // STRINGS
  // In C++, string is not a data type (as it is in JavaScript and many other languages) 
  // It is a class, and so we must write #include <string> at the top of the document
  string greeting = "Hello";
  
  // VOID
  // A common use of void is to define functions which don't return anything
  void printMessage() {
    cout << "Hello, world!";
  };
  
  return 0;
}

与 JavaScript 不同,C++ 为开发人员提供了大量内存管理的方法。在 C++ 中,每声明一个变量时,我们也会决定要保留多少内存。例如,普通的 char 通常只包含8位(1字节),这就将其用途限制为 ISO Latin 表的255个字符。相比之下,wchar_t 包含16或32位,虽然占用了更多内存,但允许我们能够访问更多种类的 Unicode 字符。

在整型中可以找到最多的种类,其中基本的 int 关键字可以与关键字 shortlonglong long 以及 “signedness” 关键字 signedunsigned 结合使用。 。

基本的 int 类型的取值范围是系统体系建议的自然范围。在 64 位操作系统上通常是 32 位。这就意味着这样的一个有符号的变量的取值范围在 -2,147,483,648 和 2,147,483,647 之间,而无符号变量的取值范围是 0 到 4,294,967,295 之间。

如果你能够确认自己的变量取值范围比较小,可以使用 short int 来节省内存。或者如果你正在处理非常大的整数,你可以使用 unsigned long long int 来处理 64 位的数字,其取值上限为 2^64 - 1

为什么内存至关重要:一个关于时间溢出的用例

使用 64 位变量(例如 long long int)可以让计算机表示未来约 2.92 亿年的日期。这似乎是没什么必要的,但它实际上解决了一个非常实际的问题。

按照惯例,计算中的大多数日期都是用 Unix 时间来表示的,该时间的起始日期是 1970 年 1 月 1 日午夜,精确到秒。如果将 Unix 时间存储在有符号的 32 位变量中,可记录的最大值为 2,147,483,647。虽然看起来很大,但考虑到它每一秒都在增长,实际上 20 亿并不能让我们用得太久。

实际上 32 位系统上记录的日期将在 2038 年 1 月 19 日 UTC(恰好是 03:14:07 )达到最大值。当这种情况发生时,日期将会变为负的 2,147,483,647,这个时间是 1901 年 12 月 13 日。它被称为 2038 问题,并且它导致了许多标题的出现,例如“所有计算机将在 2038 年完蛋” —— 由英国小报 Metro 提供。

这个令人震惊的标题可能并非事实,但是当 2038 年到来时,这个问题可能会导致 32 位操作系统甚至是整个旧版本的编程语言出现问题。我第一次遇到这个问题时正在用 PHP,在 5.2 版本之前没有内置的方式能够记录超过 2038 年的日期。(JavaScript 使用了 64 位系统来处理日期,所以我们 JavaScript 程序员不用担心这个)

2038 问题证明了我们自己管理内存的潜在用处。在需要较小取值范围的地方可以节省内存。在需要更大取值范围的场合,可以确保我们的系统能够拥有足够的内存。

JavaScript 中的内存管理

“JavaScript 在创建对象时自动分配内存,并在不再使用时释放它(垃圾回收)。这种自动化处理可能会引起混乱:它可能会给程序员带来错误的暗示,即他们不需要担心内存管理问题。“ —— MDN

JavaScript被称为“自动垃圾回收”语言。它用 mark-and-sweep 算法来检查哪些内存是活动的,哪些是“垃圾”。然后收集器可以释放“垃圾”,将未使用的内存还给操作系统。

自动垃圾回收是高级语言的一个特征,它有助于释放内存——不需要通过程序员的明确指示就可以告诉它不再需要。有关 JavaScript 中垃圾回收机制的信息,请查看这篇文章MDN’s page on Memory Management

垃圾回收是一个强大的自动内存管理系统,但它并非万无一失。特别是所谓的“不需要的引用”可能会导致内存泄漏,这意味着程序占用的内存比实际需要的多,从而降低了内存的效率。但是如果我们能够意识到内存泄漏的风险,就可以采取措施将其删除。

意外的使用全局变量是导致内存泄漏的一个常见原因。当我们在 JavaScript 代码中没有用关键字 varletconst 定义变量时,那么它会自动被认为是一个全局变量。除非已定义了 foo,否则表达式 foo =“bar” 相当于 window.foo = "bar"

像 ESLint 这样的 linting 工具可以帮助你找出这样的错误,但是 JavaScript 内置的严格模式也可以将它们标记为错误,从而防止意外使用全局变量。要激活严格模式,只需在脚本或函数的开头加入"use strict";。有关从代码中去除内存泄漏风险的更多方法,请参阅这篇文章

JavaScript 中的类型

还有一些方法可以指定变量类型并在 JavaScript 中创建自己的类型,这种方式让人想到低级语言。最流行和最全面的解决方案是 TypeScript,它是 JavaScript 的语法超集,为语言添加了静态类型选项。

在 TypeScript 上有很多不错的资源,足以说明它是能确保你代码可扩展性而且没有错误的好方法,它可以帮助我们避免本文在前面关于“强制类型”那一节中看到的那种不直观的结果。 TypeScript 的文件扩展名是 .ts,还有一个等效的 .jsx.tsx。对初学者来说最好的一篇文章是5分钟入门 TypeScript

值得注意的是,还有一些针对不同 JavaScript 技术的类型注释解决方案。例如你可以将官方的 PropTypes node module 添加到你的 React 项目中。这使你可以记录传递给组件的 props 的预期数据类型以及设置默认值。特别是当与像 ESLint 这样的 linter 结合使用时,PropTypes 是基于 React 的设置的强大补充。

结论

总的来说,我希望本文有助于阐明 C++ 这样的低级语言和 JavaScript 这类高级语言之间的一些差异。

我也希望它能够为你提供一种工具,以 TypeScript 或 PropTypes 的形式将 C++ 中的一些好处带入 JavaScript,并可以影响和改进 JavaScript 中的内存管理。

如果你对 C++ 有深入的理解,并且想要了解更多关于 JavaScript 的实现方式,最好的去处可能是官方 V8 网站或者官方 Git repo。Happy coding!


本文首发微信公众号:前端先锋

欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章


欢迎继续阅读本专栏其它高赞文章:

查看原文

赞 17 收藏 13 评论 1

AUI素材网 赞了文章 · 2019-04-24

2019前端面试题汇总(主要为Vue)

毕业之后就在一直合肥小公司工作,没有老司机、没有技术氛围,在技术的道路上我只能独自摸索。老板也只会画饼充饥,前途一片迷茫看不到任何希望。于是乎,我果断辞职,在新年开工之际来到杭州,这里的互联网公司应该是合肥的几十倍吧。。。。
刚来3天,面试了几家公司,有些规模比较小,有些是创业公司,也有些已经发展的不错了;今天把最近的面试题目做个汇总,也给自己复个盘,由于我的技术栈主要为Vue,所以大部分题目都是Vue开发相关的。

1. 谈谈你对MVVM开发模式的理解

MVVM分为Model、View、ViewModel三者。
Model 代表数据模型,数据和业务逻辑都在Model层中定义;
View 代表UI视图,负责数据的展示;
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
ModelView 并无直接关联,而是通过 ViewModel 来进行联系的,ModelViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
这种模式实现了 ModelView 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom

2. Vue 有哪些指令?

v-html、v-show、v-if、v-for等等

3. v-if 和 v-show 有什么区别?

v-show 仅仅控制元素的显示方式,将 display 属性在 block 和 none 来回切换;而v-if会控制这个 DOM 节点的存在与否。当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。

4. 简述Vue的响应式原理

当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。
每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

5. Vue中如何在组件内部实现一个双向数据绑定?

假设有一个输入框组件,用户输入时,同步父组件页面中的数据
具体思路:父组件通过 props 传值给子组件,子组件通过 $emit 来通知父组件修改相应的props值,具体实现如下:

import Vue from 'vue'

const component = {
  props: ['value'],
  template: `
    <div>
      <input type="text" @input="handleInput" :value="value">
    </div>
  `,
  data () {
    return {
    }
  },
  methods: {
    handleInput (e) {
      this.$emit('input', e.target.value)
    }
  }
}

new Vue({
  components: {
    CompOne: component
  },
  el: '#root',
  template: `
    <div>
      <comp-one :value1="value" @input="value = arguments[0]"></comp-one>
    </div>
  `,
  data () {
    return {
      value: '123'
    }
  }
})

可以看到,当输入数据时,父子组件中的数据是同步改变的:
Image 1.png

Image 2.png

我们在父组件中做了两件事,一是给子组件传入props,二是监听input事件并同步自己的value属性。那么这两步操作能否再精简一下呢?答案是可以的,你只需要修改父组件:

template: `
    <div>
      <!--<comp-one :value1="value" @input="value = arguments[0]"></comp-one>-->
      <comp-one v-model="value"></comp-one>
    </div>
  `

v-model 实际上会帮我们完成上面的两步操作。

6. Vue中如何监控某个属性值的变化?

比如现在需要监控data中,obj.a 的变化。Vue中监控对象属性的变化你可以这样:

watch: {
      obj: {
      handler (newValue, oldValue) {
        console.log('obj changed')
      },
      deep: true
    }
  }

deep属性表示深层遍历,但是这么写会监控obj的所有属性变化,并不是我们想要的效果,所以做点修改:

watch: {
   'obj.a': {
      handler (newName, oldName) {
        console.log('obj.a changed')
      }
   }
  }

还有一种方法,可以通过computed 来实现,只需要:

computed: {
    a1 () {
      return this.obj.a
    }
}

利用计算属性的特性来实现,当依赖改变时,便会重新计算一个新值。

7. Vue中给data中的对象属性添加一个新的属性时会发生什么,如何解决?

示例:

<template>
  <div>
    <ul>
      <li v-for="value in obj" :key="value">
        {{value}}
      </li>
    </ul>
    <button @click="addObjB">添加obj.b</button>
  </div>
</template>
<script>
export default {
  data () {
    return {
      obj: {
        a: 'obj.a'
      }
    }
  },
  methods: {
    addObjB () {
      this.obj.b = 'obj.b'
      console.log(this.obj)
    }
  }
}
</script>
<style></style>

点击button会发现,obj.b 已经成功添加,但是视图并未刷新:
Image 3.png

Image 4.png

原因在于在Vue实例创建时,obj.b并未声明,因此就没有被Vue转换为响应式的属性,自然就不会触发视图的更新,这时就需要使用Vue的全局api $set():

addObjB () {
      // this.obj.b = 'obj.b'
      this.$set(this.obj, 'b', 'obj.b')
      console.log(this.obj)
    }

$set()方法相当于手动的去把obj.b处理成一个响应式的属性,此时视图也会跟着改变了:
Image 5.png

8. delete和Vue.delete删除数组的区别

delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。
Vue.delete直接删除了数组 改变了数组的键值。

    var a=[1,2,3,4]
    var b=[1,2,3,4]
    delete a[1]
    console.log(a)
    this.$delete(b,1)
    console.log(b)

Image 6.png

Image 7.png

9.如何优化SPA应用的首屏加载速度慢的问题?

  • 将公用的JS库通过script标签外部引入,减小app.bundel的大小,让浏览器并行下载资源文件,提高下载速度;
  • 在配置 路由时,页面和组件使用懒加载的方式引入,进一步缩小 app.bundel 的体积,在调用某个组件时再加载对应的js文件;
  • 加一个首屏 loading 图,提升用户体验;

10. 前端如何优化网站性能?

  1. 减少 HTTP 请求数量

在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信。浏览器与服务器需要经过三次握手,每次握手需要花费大量时间。而且不同浏览器对资源文件并发请求数量有限(不同浏览器允许并发数),一旦 HTTP 请求数量达到一定数量,资源请求就存在等待状态,这是很致命的,因此减少 HTTP 的请求数量可以很大程度上对网站性能进行优化。

    • CSS Sprites:国内俗称 CSS 精灵,这是将多张图片合并成一张图片达到减少 HTTP 请求的一种解决方案,可以通过 CSS background 属性来访问图片内容。这种方案同时还可以减少图片总字节数。
    • 合并 CSS 和 JS 文件:现在前端有很多工程化打包工具,如:grunt、gulp、webpack等。为了减少 HTTP 请求数量,可以通过这些工具再发布前将多个 CSS 或者 多个 JS 合并成一个文件。
    • 采用 lazyLoad:俗称懒加载,可以控制网页上的内容在一开始无需加载,不需要发请求,等到用户操作真正需要的时候立即加载出内容。这样就控制了网页资源一次性请求数量。
    1. 控制资源文件加载优先级

    浏览器在加载 HTML 内容时,是将 HTML 内容从上至下依次解析,解析到 link 或者 script 标签就会加载 href 或者 src 对应链接内容,为了第一时间展示页面给用户,就需要将 CSS 提前加载,不要受 JS 加载影响。
    一般情况下都是 CSS 在头部,JS 在底部。

    1. 利用浏览器缓存
      浏览器缓存是将网络资源存储在本地,等待下次请求该资源时,如果资源已经存在就不需要到服务器重新请求该资源,直接在本地读取该资源。
    2. 减少重排(Reflow)
      基本原理:重排是 DOM 的变化影响到了元素的几何属性(宽和高),浏览器会重新计算元素的几何属性,会使渲染树中受到影响的部分失效,浏览器会验证 DOM 树上的所有其它结点的 visibility 属性,这也是 Reflow 低效的原因。如果 Reflow 的过于频繁,CPU 使用率就会急剧上升。

    减少 Reflow,如果需要在 DOM 操作时添加样式,尽量使用 增加 class 属性,而不是通过 style 操作样式。

    1. 减少 DOM 操作
    2. 图标使用 IconFont 替换

    11. 网页从输入网址到渲染完成经历了哪些过程?

    大致可以分为如下7步:

    1. 输入网址;
    2. 发送到DNS服务器,并获取域名对应的web服务器对应的ip地址;
    3. 与web服务器建立TCP连接;
    4. 浏览器向web服务器发送http请求;
    5. web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地址);
    6. 浏览器下载web服务器返回的数据及解析html源文件;
    7. 生成DOM树,解析css和js,渲染页面,直至显示完成;

    12. jQuery获取的dom对象和原生的dom对象有何区别?

    js原生获取的dom是一个对象,jQuery对象就是一个数组对象,其实就是选择出来的元素的数组集合,所以说他们两者是不同的对象类型不等价。

    • 原生DOM对象转jQuery对象:
    var box = document.getElementById('box');
    var $box = $(box);
    • jQuery对象转原生DOM对象:
    var $box = $('#box');
    var box = $box[0];

    13. jQuery如何扩展自定义方法

    (jQuery.fn.myMethod=function () {
           alert('myMethod');
    })
    // 或者:
    (function ($) {
            $.fn.extend({
                 myMethod : function () {
                      alert('myMethod');
                 }
            })
    })(jQuery)

    使用:

    $("#div").myMethod();

    目前来看公司面试的问题还是比较基础的,但是对于某些只追求会用并不研究其原理的同学来说可能就没那么容易了。所以大家不仅要追求学习的广度,更要追求深度。
    OK,希望自己能早日拿到心仪的offer.

    参考:
    浅谈网站性能之前端性能优化

    查看原文

    赞 529 收藏 391 评论 47

    AUI素材网 赞了文章 · 2019-04-24

    2019前端面试题汇总(主要为Vue)

    毕业之后就在一直合肥小公司工作,没有老司机、没有技术氛围,在技术的道路上我只能独自摸索。老板也只会画饼充饥,前途一片迷茫看不到任何希望。于是乎,我果断辞职,在新年开工之际来到杭州,这里的互联网公司应该是合肥的几十倍吧。。。。
    刚来3天,面试了几家公司,有些规模比较小,有些是创业公司,也有些已经发展的不错了;今天把最近的面试题目做个汇总,也给自己复个盘,由于我的技术栈主要为Vue,所以大部分题目都是Vue开发相关的。

    1. 谈谈你对MVVM开发模式的理解

    MVVM分为Model、View、ViewModel三者。
    Model 代表数据模型,数据和业务逻辑都在Model层中定义;
    View 代表UI视图,负责数据的展示;
    ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
    ModelView 并无直接关联,而是通过 ViewModel 来进行联系的,ModelViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
    这种模式实现了 ModelView 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom

    2. Vue 有哪些指令?

    v-html、v-show、v-if、v-for等等

    3. v-if 和 v-show 有什么区别?

    v-show 仅仅控制元素的显示方式,将 display 属性在 block 和 none 来回切换;而v-if会控制这个 DOM 节点的存在与否。当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。

    4. 简述Vue的响应式原理

    当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。
    每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

    5. Vue中如何在组件内部实现一个双向数据绑定?

    假设有一个输入框组件,用户输入时,同步父组件页面中的数据
    具体思路:父组件通过 props 传值给子组件,子组件通过 $emit 来通知父组件修改相应的props值,具体实现如下:

    import Vue from 'vue'
    
    const component = {
      props: ['value'],
      template: `
        <div>
          <input type="text" @input="handleInput" :value="value">
        </div>
      `,
      data () {
        return {
        }
      },
      methods: {
        handleInput (e) {
          this.$emit('input', e.target.value)
        }
      }
    }
    
    new Vue({
      components: {
        CompOne: component
      },
      el: '#root',
      template: `
        <div>
          <comp-one :value1="value" @input="value = arguments[0]"></comp-one>
        </div>
      `,
      data () {
        return {
          value: '123'
        }
      }
    })

    可以看到,当输入数据时,父子组件中的数据是同步改变的:
    Image 1.png

    Image 2.png

    我们在父组件中做了两件事,一是给子组件传入props,二是监听input事件并同步自己的value属性。那么这两步操作能否再精简一下呢?答案是可以的,你只需要修改父组件:

    template: `
        <div>
          <!--<comp-one :value1="value" @input="value = arguments[0]"></comp-one>-->
          <comp-one v-model="value"></comp-one>
        </div>
      `

    v-model 实际上会帮我们完成上面的两步操作。

    6. Vue中如何监控某个属性值的变化?

    比如现在需要监控data中,obj.a 的变化。Vue中监控对象属性的变化你可以这样:

    watch: {
          obj: {
          handler (newValue, oldValue) {
            console.log('obj changed')
          },
          deep: true
        }
      }

    deep属性表示深层遍历,但是这么写会监控obj的所有属性变化,并不是我们想要的效果,所以做点修改:

    watch: {
       'obj.a': {
          handler (newName, oldName) {
            console.log('obj.a changed')
          }
       }
      }

    还有一种方法,可以通过computed 来实现,只需要:

    computed: {
        a1 () {
          return this.obj.a
        }
    }

    利用计算属性的特性来实现,当依赖改变时,便会重新计算一个新值。

    7. Vue中给data中的对象属性添加一个新的属性时会发生什么,如何解决?

    示例:

    <template>
      <div>
        <ul>
          <li v-for="value in obj" :key="value">
            {{value}}
          </li>
        </ul>
        <button @click="addObjB">添加obj.b</button>
      </div>
    </template>
    <script>
    export default {
      data () {
        return {
          obj: {
            a: 'obj.a'
          }
        }
      },
      methods: {
        addObjB () {
          this.obj.b = 'obj.b'
          console.log(this.obj)
        }
      }
    }
    </script>
    <style></style>

    点击button会发现,obj.b 已经成功添加,但是视图并未刷新:
    Image 3.png

    Image 4.png

    原因在于在Vue实例创建时,obj.b并未声明,因此就没有被Vue转换为响应式的属性,自然就不会触发视图的更新,这时就需要使用Vue的全局api $set():

    addObjB () {
          // this.obj.b = 'obj.b'
          this.$set(this.obj, 'b', 'obj.b')
          console.log(this.obj)
        }

    $set()方法相当于手动的去把obj.b处理成一个响应式的属性,此时视图也会跟着改变了:
    Image 5.png

    8. delete和Vue.delete删除数组的区别

    delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。
    Vue.delete直接删除了数组 改变了数组的键值。

        var a=[1,2,3,4]
        var b=[1,2,3,4]
        delete a[1]
        console.log(a)
        this.$delete(b,1)
        console.log(b)

    Image 6.png

    Image 7.png

    9.如何优化SPA应用的首屏加载速度慢的问题?

    • 将公用的JS库通过script标签外部引入,减小app.bundel的大小,让浏览器并行下载资源文件,提高下载速度;
    • 在配置 路由时,页面和组件使用懒加载的方式引入,进一步缩小 app.bundel 的体积,在调用某个组件时再加载对应的js文件;
    • 加一个首屏 loading 图,提升用户体验;

    10. 前端如何优化网站性能?

    1. 减少 HTTP 请求数量

    在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信。浏览器与服务器需要经过三次握手,每次握手需要花费大量时间。而且不同浏览器对资源文件并发请求数量有限(不同浏览器允许并发数),一旦 HTTP 请求数量达到一定数量,资源请求就存在等待状态,这是很致命的,因此减少 HTTP 的请求数量可以很大程度上对网站性能进行优化。

    • CSS Sprites:国内俗称 CSS 精灵,这是将多张图片合并成一张图片达到减少 HTTP 请求的一种解决方案,可以通过 CSS background 属性来访问图片内容。这种方案同时还可以减少图片总字节数。
    • 合并 CSS 和 JS 文件:现在前端有很多工程化打包工具,如:grunt、gulp、webpack等。为了减少 HTTP 请求数量,可以通过这些工具再发布前将多个 CSS 或者 多个 JS 合并成一个文件。
    • 采用 lazyLoad:俗称懒加载,可以控制网页上的内容在一开始无需加载,不需要发请求,等到用户操作真正需要的时候立即加载出内容。这样就控制了网页资源一次性请求数量。
    1. 控制资源文件加载优先级

    浏览器在加载 HTML 内容时,是将 HTML 内容从上至下依次解析,解析到 link 或者 script 标签就会加载 href 或者 src 对应链接内容,为了第一时间展示页面给用户,就需要将 CSS 提前加载,不要受 JS 加载影响。
    一般情况下都是 CSS 在头部,JS 在底部。

    1. 利用浏览器缓存
      浏览器缓存是将网络资源存储在本地,等待下次请求该资源时,如果资源已经存在就不需要到服务器重新请求该资源,直接在本地读取该资源。
    2. 减少重排(Reflow)
      基本原理:重排是 DOM 的变化影响到了元素的几何属性(宽和高),浏览器会重新计算元素的几何属性,会使渲染树中受到影响的部分失效,浏览器会验证 DOM 树上的所有其它结点的 visibility 属性,这也是 Reflow 低效的原因。如果 Reflow 的过于频繁,CPU 使用率就会急剧上升。

    减少 Reflow,如果需要在 DOM 操作时添加样式,尽量使用 增加 class 属性,而不是通过 style 操作样式。

    1. 减少 DOM 操作
    2. 图标使用 IconFont 替换

    11. 网页从输入网址到渲染完成经历了哪些过程?

    大致可以分为如下7步:

    1. 输入网址;
    2. 发送到DNS服务器,并获取域名对应的web服务器对应的ip地址;
    3. 与web服务器建立TCP连接;
    4. 浏览器向web服务器发送http请求;
    5. web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地址);
    6. 浏览器下载web服务器返回的数据及解析html源文件;
    7. 生成DOM树,解析css和js,渲染页面,直至显示完成;

    12. jQuery获取的dom对象和原生的dom对象有何区别?

    js原生获取的dom是一个对象,jQuery对象就是一个数组对象,其实就是选择出来的元素的数组集合,所以说他们两者是不同的对象类型不等价。

    • 原生DOM对象转jQuery对象:
    var box = document.getElementById('box');
    var $box = $(box);
    • jQuery对象转原生DOM对象:
    var $box = $('#box');
    var box = $box[0];

    13. jQuery如何扩展自定义方法

    (jQuery.fn.myMethod=function () {
           alert('myMethod');
    })
    // 或者:
    (function ($) {
            $.fn.extend({
                 myMethod : function () {
                      alert('myMethod');
                 }
            })
    })(jQuery)

    使用:

    $("#div").myMethod();

    目前来看公司面试的问题还是比较基础的,但是对于某些只追求会用并不研究其原理的同学来说可能就没那么容易了。所以大家不仅要追求学习的广度,更要追求深度。
    OK,希望自己能早日拿到心仪的offer.

    参考:
    浅谈网站性能之前端性能优化

    查看原文

    赞 529 收藏 391 评论 47

    AUI素材网 关注了用户 · 2018-06-06

    luckness @luckness

    关注 5061

    AUI素材网 关注了用户 · 2018-06-06

    改名字很伤神 @gaimingzihenshangshen

    它可以工作,但是我不知道为什么,所以谁也别碰它!

    关注 12508

    AUI素材网 关注了用户 · 2018-06-06

    路人 @tscript

    关注 485

    AUI素材网 关注了用户 · 2018-06-06

    toBeTheLight @tobethelight

    熟练掌握 TS(0.5/1)
    学习经济学(1/1)
    学习数学知识(0/n)
    学习编译原理(0/1)
    文笔更好一些(1/1)

    关注 26536

    AUI素材网 关注了用户 · 2018-06-06

    OBKoro1 @obkoro1

    前端进阶积累、前端算法、开箱即用代码块:http://obkoro1.com/web_accumu...

    关注 3217

    认证与成就

    • 获得 1 次点赞
    • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

    擅长技能
    编辑

    (゚∀゚ )
    暂时没有

    开源项目 & 著作
    编辑

    (゚∀゚ )
    暂时没有

    注册于 2017-12-15
    个人主页被 294 人浏览