Skip to content

Latest commit

 

History

History
822 lines (579 loc) · 24.1 KB

interview-prepare.md

File metadata and controls

822 lines (579 loc) · 24.1 KB

NODEJS

nodejs的特点

单线程

非阻塞IO

事件驱动

每个线程需要耗费大约2MB内存。也就是说,理论上,一个8GB内存的服务器可以同时连接的最大用户数为4000个左右。

事件循环

模块

需要复习一下模块

module

CommonJS 中的 require/exports 和 ES6 中的 import/export 区别?

- CommonJS 模块的重要特性是加载时执行,即脚本代码在 require 的时候,就会全部执行。一旦出现某个模块被”循环加载”,就只输出已经执行的部分,还未执行的部分不会输出。
- ES6 模块是动态引用,如果使用 import 从一个模块加载变量,那些变量不会被缓存,而是成为一个指向被加载模块的引用,需要开发者自己保证,真正取值的时候能够取到值。
- import/export 最终都是编译为 require/exports 来执行的。
- CommonJS 规范规定,每个模块内部,module 变量代表当前模块。这个变量是一个对象,它的 exports 属性(即 module.exports )是对外的接口。加载某个模块,其实是加载该模块的 module.exports 属性。
- export 命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。

- CommonJS运行时加载
  CommonJS 模块输出的是一个值的拷贝,

- ES6编译时加载(或叫静态加载)
  ES6 模块是动态引用 ES6 模块输出的是值的引用。
  export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。
  import命令具有提升效果,会提升到整个模块的头部,首先执行。
  如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次。

export 如果后面跟的是会变量提升的 var/function,那么会变量提升 module.exports/exports 不会变量提升

exports 与 module.exports 的区别

nodejs 暴露模块需要用 module.exports,其实 exports = module.exports,当我们给 epxorts.a = xxx 时,其实就是在 module.exports 上加属性

这就是为什么不能给 exports 赋值的原因,即赋值会改变 exports 的指向

event

http/http2/https url buffer fs path querystring

console debugger global process child_process readline cluster

npm

npm init

npm init egg --type=simple

// 等价于
npx create-egg --type=simple

koa

express

egg

egg 周边

egg egg-init egg-bin egg-scripts

es6

callback promise generator async

string

"z" === "z"; // true
"\172" === "z"; // true 8进制
"\x7A" === "z"; // true 16进制
"\u007A" === "z"; // true utf-16编码
"\u{7A}" === "z"; // true utf-16编码

为什么"\u{20BB7}" === "\uD842\uDFB7" === "𠮷"

简单讲就是 utf-16 编码转换

Number

由于 JavaScript 采用 IEEE 754 标准,数值存储为 64 位双精度格式,数值精度最多可以达到 53 个二进制位(1 个隐藏位与 52 个有效位)。 范围: -Math.pow(2,53) ~ Math.pow(2,53) 不包括两个端点

32 为的浮点数 分为 3 部分:

第一部分是符号位,用 s 表示,代表正负,要记住的是在浮点数的范围内,所有数字都是有符号的; 第二部分是指数位,用 e 表示,代表指数,用 8 位 bit 表示的数字范围是 0255,为了同时表示大数和小数,我们把 0255 去掉头尾(0,255 后面会用到)的 1254 去映射到-126127,这样同时可以表示最大最小数字; 第三部分是有效数位,用 f 表示,代表的是有效的数位; 综合上述表示和科学计数法,我们的浮点数就可以表示为公式

(-1)^s * 1.f * 2^e

函数

箭头函数有几个使用注意点。

(1)函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象。

(2)不可以当作构造函数,也就是说,不可以使用 new 命令,否则会抛出一个错误。

(3)不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

(4)不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。

array

ES5 对空位的处理,已经很不一致了,大多数情况下会忽略空位。

forEach(), filter(), reduce(), every() 和 some()都会跳过空位。 map()会跳过空位,但会保留这个值 join()和 toString()会将空位视为 undefined,而 undefined 和 null 会被处理成空字符串。

ES6 则是明确将空位转为 undefined。

[, "a", undefined, null].join("#"); // "#a##"
[, "a", undefined, null].toString(); // ",a,,"

Object

Object.create

Object.create 第二个参数是对象描述

const obj = Object.create({}, { p: { value: 42 } }); // p是不可枚举的
Object.values(obj); // []
const obj = Object.create(
  {},
  {
    p: {
      value: 42,
      enumerable: true,
    },
  }
);
Object.values(obj); // [42]

对象与数组的遍历

对象的扩展运算符(...)用于取出参数对象自身的所有可遍历属性,拷贝到当前对象之中。

举个栗子

var a = { a: 1 };
Object.defineProperty(a, "aa", {
  value: 3,
});
var b = { b: 2 };
b.__proto__ = a;

Object.defineProperty(b, "c", {
  value: 3,
});
b[Symbol()] = 4;

Object.keys(b); // ["b"]  返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性).

for (var i in b) {
  console.log(i, ":", b[i]);
} // b : 2 a : 1   循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)

Object.getOwnPropertyNames(obj); // ["b", "c"] 返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性).
Reflect.ownKeys(b); // ["b", "c", Symbol()] 返回一个数组,包含对象自身的所有属性,不管属性名是Symbol或字符串,也不管是否可枚举.

var c = { ...b }; // {b: 2, Symbol(): 4}

Promise

async/await

async继发与并发

// 继发
let foo = await getFoo();
let bar = await getBar();


// 并发
// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
// 继发
// 方法一
async function dbFuc(db) { //这里不需要 async
  let docs = [{}, {}, {}];

  for (let doc of docs) {
    await db.post(doc);
  }
}

// 方法二
async function dbFuc(db) {
  let docs = [{}, {}, {}];

  await docs.reduce(async (_, doc) => {
    await _;
    await db.post(doc);
  }, undefined);
}

// 并发
function dbFuc(db) { //这里不需要 async
  let docs = [{}, {}, {}];

  // 可能得到错误结果
  docs.forEach(async function (doc) {
    await db.post(doc);
  });
}

async function dbFuc(db) {
  let docs = [{}, {}, {}];
  let promises = docs.map((doc) => db.post(doc));

  let results = await Promise.all(promises);
  console.log(results);
}

// 或者使用下面的写法

async function dbFuc(db) {
  let docs = [{}, {}, {}];
  let promises = docs.map((doc) => db.post(doc));

  let results = [];
  for (let promise of promises) {
    results.push(await promise);
  }
  console.log(results);
}

class

super

super指向当前对象的原型对象

注意,super 关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。 目前,只有对象方法的简写法可以让 JavaScript 引擎确认,定义的是对象的方法。

// 报错
const obj = {
  foo: super.foo,
};

// 报错
const obj = {
  find: () => super.foo,
};

// 报错
const obj = {
  find: function() {
    return super.foo;
  },
};
// 正确
const obj = {
  foo: "world",
  find() {
    return super.foo;
  },
};

扩展运算符的解构赋值,不能复制继承自原型对象的属性

const o = Object.create({ x: 1, y: 2 });
o.z = 3;

let { x, ...newObj } = o;
let { y, z } = newObj;
x; // 1
y; // undefined
z; // 3

注意,简写的对象方法不能用作构造函数,会报错。

const obj = {
  f() {
    this.foo = "bar";
  },
};

new obj.f(); // 报错

如果对象的方法使用了取值函数(getter)和存值函数(setter),则 name 属性不是在该方法上面,而是该方法的属性的描述对象的 get 和 set 属性上面,返回值是方法名前加上 get 和 set。

const obj = {
  get foo() {},
  set foo(x) {},
};

obj.foo.name;
// TypeError: Cannot read property 'name' of undefined

const descriptor = Object.getOwnPropertyDescriptor(obj, "foo");

descriptor.get.name; // "get foo"
descriptor.set.name; // "set foo"

函数的 name 属性

new Function().name; // "anonymous"

var doSomething = function() {
  // ...
};
doSomething.name; // "doSomething"
doSomething.bind().name; // "bound doSomething"

const key1 = Symbol("description");
const key2 = Symbol();
let obj = {
  [key1]() {},
  [key2]() {},
};
obj[key1].name; // "[description]"
obj[key2].name; // ""

Object.assign

  • 可以用来处理数组,但是会把数组视为对象 Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3]

  • 取值函数的处理

const source = {
  get foo() {
    return 1;
  },
};
const target = {};

Object.assign(target, source);
// { foo: 1 }

export

export *命令会忽略模块的 default 方法

export var a = 1;
// 或者
var a = 1;
export { a };
export defalut 1
// modules.js
function add(x, y) {
  return x * y;
}
export { add as default };
// 等同于
// export default add;

// app.js
import { default as foo } from "modules";
// 等同于
// import foo from 'modules';

super

  • super的指向以及super中this的指向问题
super可以作为函数和对象使用
作为函数时指向父类的构造函数,只能在构造函数中使用
作为对象时,在普通方法中指向父类原型对象,在静态方法中指向父类
super调用的方法中this指向,普通方法中this指向自身实例,静态方法中指向自身类

super在普通方法中等于this

易错题

class A {
  constructor() {
    this.x = 1;
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
    super.x = 3; // super等于this
    console.log(super.x); // undefined
    console.log(this.x); // 3
  }
}

let b = new B();

babel

注意 babel 只转换新的句法(语法),不会转换新的 API,比如 Iterator、Generator、Set、Map、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转码。

typescript

JS

performance

performance.timing

https://developer.mozilla.org/zh-CN/docs/Web/API/PerformanceTiming

Object.defineProperty

先看 configurable,再看 writable configurable 为 false 表示不能修改属性描述符,不能删除属性 configurable 和 writable 同时为 fasle 时,不可以修改任何描述符 configurable 为 false 时,只可以修改 writable

扩展:

严格模式下 o.a 会报错

Object.isExtensible() Object.seal() // 方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。 Object.isSealed() Object.freeze() // 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。 Object.isFrozen() Object.preventExtensions() // 方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。

正则

vue

vue vue-router vuex vue-ssr nuxt 实现自己的 vue2 vue3

// TODO:vue-cli

vue面试题

  • 描述下diff算法

Vue 是如何监控到子组件修改了props属性并给出警告的

vue3

react

实现一个 react

webpack

优化

  • 域名预解析

  • 域名分散处理, 突破浏览器对单个域名的最大并发连接数 分散到 img0.guoweiwei.com/img1.guoweiwei.com/img2.guoweiwei.com/…等不同域名

浏览器

缓存

prefetch preload

prefetch(预取):将来某些导航下可能需要的资源 preload(预加载):当前导航下可能需要资源

与 prefetch 指令相比,preload 指令有许多不同之处:

preload chunk 会在父 chunk 加载时,以并行方式开始加载。prefetch chunk 会在父 chunk 加载结束后开始加载。 preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。 preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。 浏览器支持程度不同。

网络

css

BFC

什么是BFC?BFC的好处是什么? 如何创建BFC?

百分比

display: none 和visibility: hidden 和opacity: 0的区别

display: none; DOM 结构:浏览器不会渲染 display 属性为 none 的元素,不占据空间; 事件监听:无法进行 DOM 事件监听; 性能:动态改变此属性时会引起重排,性能较差; 继承:不会被子元素继承,毕竟子类也不会被渲染; transition:transition 不支持 display。

visibility: hidden; DOM 结构:元素被隐藏,但是会被渲染不会消失,占据空间; 事件监听:无法进行 DOM 事件监听; 性 能:动态改变此属性时会引起重绘,性能较高; 继 承:会被子元素继承,子元素可以通过设置 visibility: visible; 来取消隐藏; transition:transition 不支持 visibility

opacity: 0; DOM 结构:透明度为 100%,元素隐藏,占据空间; 事件监听:可以进行 DOM 事件监听; 性 能:提升为合成层,不会触发重绘,性能较高; 继 承:会被子元素继承,且,子元素并不能通过 opacity: 1 来取消隐藏; transition:transition 支持 opacity。

flex grid布局

水平垂直居中

选择器

https://www.runoob.com/cssref/css-selectors.html

算法

手写

项目

hr面

面试题

如何做好seo

站内优化

  1. 内容优化,我们的网站是博客?落地页?论坛社区?
  2. 关键词优化
  3. 标题
  4. Meta信息号称TKD元描述,就是Title/Description/Keyword 如何查看一个网站的Meta信息?最方便的就是安装Chrome的一个插件:meta seo inspector
  5. 导航一般是面包屑导航
  6. 内链优化的有助于我们给站内不同的页面导流,传递页面权重
  7. 图片最好加ALT标签
  8. 标签嵌套层次不能太深

技术性优化

  1. 加载速度
  2. 移动适配 Google搜索的63%来自移动设备
  3. 重复内容检测 网站的重复内容过多,会让Google认为该站的质量很低,从而降低网站的评分
  4. 不要让网站出现大量404页面
  5. 重定向,不要删除之前的
  6. sitemap.xml
  7. robots.txt

站外优化

  1. 友情链接
  2. 社区推广
  3. 社交网站
  4. 掏钱买

怎么优化 通过谷歌分析,看跳出率来定位问题

线上出现一个bug 怎么定位

首先我们会有一个前端监控系统,通过这个系统我们可以看到用户的行为轨迹,可以还原一个用户现场, 其次我们会看看测试同学有没有线索,能不能还原现场, 无法还原现场的,我们会通过调试代码的方式,进行一个排查

常见的错误: 用户的数据缓存问题 脚本的版本问题 用户的数据比较特殊,比如确实某个字段, 没有进行一个容错,

怎么优化webpack打包速度

通用

  1. 提升webpack的版本
  2. 并行打包
  3. loader里面设置include\exclude
  4. 每个额外的 loader/plugin 都有启动时间。尽量少使用不同的工具。
  5. 尽量少用resolve
  6. 使用 cache-loader 启用持久化缓存

开发环境

  1. 在内存中编译,用webpack-dev-server
  2. 增量编译,开启hot
  3. Devtool 设置source-map
  4. 避免在生产环境下才会用到的工具, 如压缩代码

生产环境

  1. 多个编译时 parallel-webpack
  2. Source maps

怎么配置webpack

怎么优化网站

  1. 首屏优化
  2. 内存优化

怎么优化首屏加载速度

  1. 应用骨架屏
  2. 对代码进行分包
  3. 如果是多图片的话 进行图片懒加载
  4. 如果有很多小图标的话 就利用雪碧图
  5. 懒加载 可以按路由进行加载
  6. dns prefetch
  7. async defer
  8. preload prefetch
  9. ssr

怎么带人的

  1. 管理就是通过下属实现经营者的目标,管理只不能简单复述领导层的话,需要加上自己的理解,并变成可以执行的任务,分配给下属
  2. 主要分为业务管理、员工管理
  3. 管理团队要有一个好的、透明的晋升机制,做的好的就需要奖励,做的不好也要严厉批评
  4. 要根据下属的性格(ffs测试)、意愿、能力等综合分析,把对的人安排到对的位置上,这样才能实现1+1>2的效果
  5. 要适度的区分指示和人文关怀
  6. 面试候选人或者提拔下属,需要选择跟公司价值观一致的候选人
  7. 遇到问题,需要保护好自己的下属,自己来担责,这样下属才会有冲劲
  8. 使用目标管理,让团队成员理解目标,并需告知目标是一定要完成的
  9. 作为管理者,一定要比下属看得远,需要指引下属往对的方向发展
  10. 业务管理,分配任务,并告知详细执行,然后中间主动询问进度等,也可让下属自己汇报
  11. 让下属自己汇报自己的成绩,保证公平公正

公司的开发流程

怎么避免组员写垃圾代码

  1. eslint 代码规范
  2. code review(这里介绍公司的四个环境)

火焰图调试网站性能

顶部有平台的一般都有性能问题

项目场景

让你来设计一个瀑布流图片展示,你需要考虑哪些

无尽列表加载

大文件上传