Skip to content
On this page
  • flex拆分写法 flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。 flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。 flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。 flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。

  • css 选择器 伪类伪元素, 区别是什么, 为什么一个叫伪类一个叫伪元素,都有哪些, 哪个是一个冒号哪个是两个冒号 伪类是选择器的一种,它用于选择处于特定状态的元素,比如当它们是这一类型的第一个元素时,或者是当鼠标指针悬浮在元素上面的时候。它们表现得会像是你向你的文档的某个部分应用了一个类一样,帮你在你的标记文本中减少多余的类,让你的代码更灵活、更易于维护。 :active、:blank、:checked、:disabled、:enabled、:first-child、:first-of-type、:focus、:hover、:is() 、:not 、:target、:visited等都是伪类 伪元素以类似方式表现,不过表现得是像你往标记文本中加入全新的HTML元素一样,而不是向现有的元素上应用类。伪元素开头为双冒号::。 ::after、::before、::first-letter、::first-line

  • bfc 块格式化上下文(Block Formatting Context,BFC) 是 Web 页面的可视 CSS 渲染的一部分,是块级盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。

    • 形成bfc的条件:
      • 浮动元素:float除none以外的值
      • 绝对定位元素,position(absolute、fixed)
      • display为以下其中之一的值inline-block、table-cell、table-caption、flex
      • overflow除了visible以外的值(hidden、scroll、auto)
      • html根元素
    • bfc的特性
      • 内部的box会在垂直方向上一个一个的放置
      • 垂直方向的距离由margin决定
      • bfc的区域不会与float的元素区域重叠
      • 计算bfc高度时,浮动元素也参与计算
      • bfc就是页面上的一个独立容器,容器里面的子元素不会影响外面元素
    • BFC的应用 1、自适应两栏布局 2、清除内部浮动 3、防止margin上下重叠
    • 普通文档流布局规则 1.浮动的元素是不会被父级计算高度 2.非浮动元素会覆盖浮动元素的位置 3.margin会传递给父级 4.两个相邻元素上下margin会重叠
    • BFC布局规则 1.浮动的元素会被父级计算高度(父级触发了BFC) 2.非浮动元素不会覆盖浮动元素位置(非浮动元素触发了BFC) 3.margin不会传递给父级(父级触发了BFC) 4.两个相邻元素上下margin会重叠(给其中一个元素增加一个父级,然后让他的父级触发BFC)
  • 实现一个LazyMan,可以按照以下方式调用: LazyMan("Hank")输出: Hi! This is Hank!

LazyMan("Hank").sleep(10).eat("dinner")输出 Hi! This is Hank! //等待10秒.. Wake up after 10 Eat dinner~

LazyMan("Hank").eat("dinner").eat("supper")输出 Hi This is Hank! Eat dinner~ Eat supper~

LazyMan("Hank").sleepFirst(5).eat("supper")输出 //等待5秒 Wake up after 5 Hi This is Hank! Eat supper

class _LazyMan {
	constructor(name) {
	  this.tasks = [];
	  const task = () => {
		console.log(`Hi! This is ${name}`);
		this.next();
	  }
	  this.tasks.push(task);
	  setTimeout(() => {               // 把 this.next() 放到调用栈清空之后执行
		this.next();
	  }, 0);
	}
  
	next() {
	  const task = this.tasks.shift(); // 取第一个任务执行
	  task && task();
	}
  
	sleep(time) {
	  this._sleepWrapper(time, false);
	  return this;                     // 链式调用
	}
  
	sleepFirst(time) {
	  this._sleepWrapper(time, true);
	  return this;
	}
  
	_sleepWrapper(time, first) {
	  const task = () => {
		setTimeout(() => {
		  console.log(`Wake up after ${time}`);
		  this.next();
		}, time * 1000)
	  }
	  if (first) {
		this.tasks.unshift(task);     // 放到任务队列顶部
	  } else {
		this.tasks.push(task);        // 放到任务队列尾部
	  }
	}
  
	eat(name) {
	  const task = () => {
		console.log(`Eat ${name}`);
		this.next();
	  }
	  this.tasks.push(task);
	  return this;
	}
  }
  
  function LazyMan(name) {
	return new _LazyMan(name);
  }
  • 函数式组件的特点,以及应用场景 不需要实例化、无状态、无生命周期、无this,但是性能高 比如一些详情页面,列表界面等,它们有一个共同的特点是只需要将外部传入的数据进行展现,不需要有内部状态,不需要在生命周期钩子函数里面做处理,这时候你就可以考虑使用函数式组件。

  • 时间切片 如果任务不能在50毫秒内执行完,那么为了不阻塞主线程,将一个长任务拆分成很多个不超过50ms的小任务分散在宏任务队列中执行。 分页+requestAnimation+DocumentFragment

  • for in 与for of 的区别 for...in ES5标准,循环只遍历可枚举属性(包括它的原型链上的可枚举属性) for...of ES6标准,只可以循环可迭代对象的可迭代属性 如(Array,Map,Set,String,TypedArray,arguments 对象等等)

  • 原生实现JSON.stringify()

function JSON2String(obj){
	var arr = [];
	let type = typeof obj;
	if(Array.isArray(obj)){
		obj.forEach(item=>{
			let childType = typeof item;
			if(childType==='function' || childType==='undefined' || childType==='symbol' || (childType=='number' && ( !isFinite(item) || Number.isNaN(item) ) ) ){
				arr.push('null')
			}else{
				arr.push( JSON2String(item) );
			}
		})
		return `[${arr}]`;
	}else if(type==='object' && obj !==null){
		Object.keys(obj).forEach(key=>{
			let val = obj[key];
			let childType = typeof val;
			if(childType!=='object' &&( !isFinite(val) || Number.isNaN(val) ) ){
				arr.push(`"${key}":null`)
			}else if(childType!=='function' && childType!=='undefined' && childType!=='symbol' ){
				let child = JSON2String(val);
				arr.push(`"${key}":${child}`)
			} 
		})
		return `{${ arr.join(',') }}`
	}else if(type==='string'){
		return `"${obj}"`
	}else{
		return obj.toString()
	}
}

var obj={
	arr:[1,undefined,function(){}],
	bol:true,
	obj:{a:1,b:2,c:NaN}
}
  • 字节面试
  • common和ESModule区别
  • csrf及如何防范 CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
  • CSRF的特点

    • 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。
    • 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。
    • 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”。
    • 跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。
  • 防护策略 CSRF通常从第三方网站发起,被攻击的网站无法防止攻击发生,只能通过增强自己网站针对CSRF的防护能力来提升安全性。 上文中讲了CSRF的两个特点: CSRF(通常)发生在第三方域名。 CSRF攻击者不能获取到Cookie等信息,只是使用。 针对这两点,我们可以专门制定防护策略,如下:

  • 怎样清除浮动,浮动的概念

  • 讲下闭包 函数执行形成私有上下文,首先这里的私有变量被”保护“起来,不受外界的干扰!而且如果上下文不被释放,则里面的私有变量也会被”保存“下来,这样其下级上下文就可以操作(访问/修改)这些值了!

  • 讲下节流及实现 高频触发,规定时间内触发一次,

  • 讲下http2,然后问到多路复用是怎么复用的(对比http1) https://juejin.cn/post/6844903935648497678 多路复用、二进制分帧、头部压缩、服务端推送

  • react hook

  • 普通函数和箭头函数的区别 箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或new.target。 yield 关键字通常不能在箭头函数中使用(除非是嵌套在允许使用的函数内)。因此,箭头函数不能用作函数生成器。 由于 箭头函数没有自己的this指针,通过 call() 或 apply() 方法调用一个函数时,只能传递参数(不能绑定this---译者注),他们的第一个参数会被忽略。

  • 讲下vue3:

    • Vue2.0采用flow进行编写,而3.0源码全部采用Typescript进行开发,对Typescript支持友好
    • 源码体积优化:移除部分api(filter等),使用tree-shaking(vue2大量的api挂载在Vue对象的原型上,难以实现treeShaking)
    • 数据劫持优化:Vue3采用Proxy,性能大大提升
    • 编译优化:Vue3实现了静态模板分析,重写diff算法
    • CompositionAPI:整合业务代码的逻辑,提取公共逻辑(vue2采用mixin:命名冲突、数据来源不清晰)
    • 自定义渲染器:可以用来创建自定义渲染器,改写vue底层渲染逻辑
    • 新增fragment、Teleport、Suspense组件
  • 讲下websocket及应用场景 全双工、二进制帧 https://juejin.cn/post/7080511037320986660 优点 较少的控制开销:数据包头部协议较小,不同于http每次请求需要携带完整的头部 更强的实时性:相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少 保持创连接状态:创建通信后,可省略状态信息,不同于HTTP每次请求需要携带身份验证 更好的二进制支持:定义了二进制帧,更好处理二进制内容 支持扩展:用户可以扩展websocket协议、实现部分自定义的子协议 更好的压缩效果:Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率

  • vue2中template如何实现的 解析html,生成ast 标记静态节点 生成代码 new Function+with生成render

  • 讲下进程和线程(进程、线程是什么,线程都共享什么?) 进程是系统进行资源调度和分配的的基本单位; 线程是CPU进行资源调度和分配的最小单位 一个进程可以有多个线程,多个线程可以共享进程的进程的资源 https://cloud.tencent.com/developer/article/1688297

笔试部分

var F = function() {}; Object.prototype.a = function() { console.log('a'); }; Function.prototype.b = function() { console.log('b'); } var f = new F(); f.a(); //a f.b(); //不是undefined 报错了 F.a(); //a F.b(); //b

  • 深克隆实现 function deepClone(obj, hash = new WeakMap()){ if(obj ==null) return obj; if(obj instanceof Date) return new Date(obj); if(obj instanceof RegExp) return new RegExp(obj);

    if(typeof obj != 'object') return obj;

    if(hash.has(obj))return hash.get(obj);//防止循环引用 let cloneObj = new obj.constructor; for(let key in obj){ if(obj.hasOwnProperty(key)){ cloneObj[key] = deepClone( obj[key], hash ) } } return cloneObj;

}

  • instanceof实现 const instanceof = (A, B)=>{ let p =A; while(p){ if(p === B.prototype){ return true; } p = p.proto; } return false; }
  • 火币面试
  • 重绘、重排

  • js动画有几种 css和js 怎么还多了canvas?

  • 页面适配

  • 继承的几种方式,原型式继承的缺点 javascript直接实现; SVG(可伸缩矢量图形); CSS3 transition; CSS3 animation; Canvas动画; requestAnimationFrame;

  • vue响应式原理

  • 父子组件生命周期执行顺序

    • 加载渲染过程 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
    • 销毁过程 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
  • 浏览器强制缓存/协商缓存 1、强缓存和对比缓存同时存在,如果强缓存还在生效期则强制缓存覆盖对比缓存,对比缓存不生效;如果强缓存不在有效期,对比缓存生效。即:强缓存优先级 > 对比缓存优先级 2、强缓存expires和cache-control同时存在时,则cache-control会覆盖expires,expires无论有没有过期,都无效。 即:cache-control优先级 > expires优先级。 3、对比缓存Etag和Last-Modified同时存在时,则Etag会覆盖Last-Modified,Last-Modified不会生效。即:ETag优先级 > Last-Modified优先级。

  • 数据缓存:localstorage sessionStorage cookie

  • Web Workers

  • 北京伽睿智能科技
  • bfc
  • 浏览器输入url都发生了什么
  • nextTick原理
  • 响应式原理
  • Vue中key的作用
  • 工作中有没有自定义指令
  • 自己封装过哪些组件(结合简历问的)
  • 性能优化
  • webpack plugin和loader实现
  • 原型和原型链
  • 闭包
  • es6用到哪些语法
  • 从0-1开发一个项目考虑哪些点(技术选型,脚手架、目录、部署)
  • git 从a分之1、2、3、4、5捡出commit3 到b分支怎么做
  • 简单算法 判断一个字符串能否形成回文(不是判断是不是回文) 例如:abcabc 可以形成回文 说了一下思路:统计字符出现次数,字符长度为偶数,字符次数为偶数可以形成回文;字符长度为奇数,字符出现一个奇数次可以形成

function Parent() {

} function Child()

// 原型链继承 优点: 简单易于实现,父类的新增的实例与属性子类都能访问 缺点: 可以在子类中增加实例属性,如果要新增加原型属性和方法需要在new 父类构造函数的后面 无法实现多继承 创建子类实例时,不能向父类构造函数中传参数 Child.prototype = new Parent;

//构造函数继承 优点: 解决了子类构造函数向父类构造函数中传递参数 可以实现多继承(call或者apply多个父类) 缺点: 方法都在构造函数中定义,无法复用 不能继承原型属性/方法,只能继承父类的实例属性和方法 function Child() { Parent.call(this) }

//组合式继承 优点: 函数可以复用 不存在引用属性问题 可以继承属性和方法,并且可以继承原型的属性和方法 缺点: 由于调用了两次父类,所以产生了两份实例 function Child() { Parent.call(this) } Child.prototype = new Parent;

//实例继承(原型式继承) 优点: 不限制调用方式 简单,易实现 缺点:不能多次继承 function create(obj) { var F = function F() { }; var clone = new F; F.prototype = obj; return clone }

//寄生式继承 缺点(同原型式继承): 原型链继承多个实例的引用类型属性指向相同,存在篡改的可能。 无法传递参数 function inherit() { var o = create(obj); o.xxx = function () {

}
return o;

}

//寄生组合式继承 function Parent() { } function Child() { Parent.call(this) } function create(Parent, Child) { Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; } create(Parent, Child)

Released under the MIT License.