首页 > 快手电商生态前端实习二面面经(已凉)
头像
Red_Ferrari
编辑于 2021-04-04 16:07
+ 关注

快手电商生态前端实习二面面经(已凉)

面的不好,很多都知道自己看过,但临场手写就写不对了,手写真耗时间,写着写着,查查错,面试就快结束了,自己承认知识掌握不扎实,仍需努力夯实基础。再次梳理一遍,对自己还是有帮助的。已凉,不过也让我认识到了自己的不足。

自我介绍

怎么学习前端的

你用过vue,知道vue的key是用来做什么的吧

key是为Vue中虚拟DOM标记的唯一id,通过这个key,我们的父节点可以更准确、更快速定位子节点.

讲一讲vue和react的区别

vue双向数据绑定,react单向,需要setState实现medel-view的转换

拓展:

  1. 数据绑定:Vue实现了双向的数据绑定,react数据流动是单向的

  2. 数据渲染:大规模的数据渲染,react更快

  3. 使用场景:React配合Redux架构适合大规模多人协作复杂项目,Vue适合小快的项目

  4. 开发风格:react推荐做法jsx + inline style把html和css都写在js了,vue是采用webpack +vue-loader单文件组件格式,html, js, css同一个文件

Vue怎么实现双向绑定的

Vue2.X通过 Object.defineProperty() 来劫持各个属性的settergetter,新版本通过Proxy劫持

要想深入讲解知识点:

  • Object.defineProperty() 来劫持各个属性的settergetter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty() 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue追踪依赖,在属性被访问和修改时通知变化。

  • vue的数据双向绑定 将MVVM作为数据绑定的入口,整合ObserverCompileWatcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observerCompile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。

拓展:代码(没写,自己总结面经顺便复习)

defineProperty 版本
// 数据
const data = {
	text: 'default'
};
const input  = document.getElementById('input');
const span  = document.getElementById('span');
// 数据劫持
Object.defineProperty(data, 'text', {
	// 数据变化 --> 修改视图
	set(newVal) {
		input.value = newVal;
		span.innerHTML = newVal;
	}
});
// 数据变化 --> 修改视图
input.addEventLisener('keyup', function(e) {
	data.text = e.target.value;
});
proxy 版本
// 数据
const data = {
	text: 'default'
};
const input  = document.getElementById('input');
const span  = document.getElementById('span');
// 数据劫持
const handler = {
	set(target, key, value) {
		target[key] = value;
		// 数据变化 --> 修改视图
		input.value = newVal;
		span.innerHTML = newVal;
		return value;
	}
};
const proxy = new Proxy(data, handler);

// 视图更改 --> 数据变化
input.addEventLisener('keyup', function(e) {
	proxy.text = e.target.value;
});


聊一聊原型链是什么

每个对象都有prototype(原型),当我们访问一个对象的属性时,在找不到的情况再会在其原型上查找是否有这个属性,再找不到会去自己 [__proto__] 关联的 prototype 对象上去找,顺着原型链知道undefined。语言组织太差,有种有货道不出的感觉。

好了,做一道题
Function.prototype.a = () => {
	console.log(1);
}

Object.prototype.b = () => {
	console.log(2);
}

function A() {}

const obj = new A();

obj.a() // Error

obj.b() // 2

A.a() // 1

A.b() // 2


解释了通过函数声明可以同时继承Function和Object原型上的方法,通过new继承只能继承Object的方法

面试官问第一个Error是什么Error,脑抽了说是引用Error(ReferenceError),实际上是TypeErro,打印的是这个结果

Uncaught TypeError: obj.a is not a function

说到继承,你写一下你知道的继承方式

这下充分暴露了自己的不足,知道的六种继承方式,并说了出来,要求手写才发现很多都写错了
function person() {
	this.kind="person";
}
person.prototype.eat = function (food) {
	console.log(this.name+" is eating "+food);
}

function student() {

}
先写了一下继承后上述prototype和proto的关系
student.prototype.__proto__ === person.prototype
原型继承
student.prototype = new person();

缺点:原型是所有子类实例共享的,改变一个其他也会改变。

该打,我没写完全对

构造继承
function student() {
    person.call(this);
}

缺点:不能继承父类原型,函数在构造函数中,每个子类实例不能共享函数,浪费内存。

这个倒是完全写对了

组合继承
function student() {
    person.call(this);
}
student.prototype = new Person();

缺点:person的构造函数会多执行了一次

哭了,又没有完全写对

原型式继承
student.prototype = Object.create(person.prototype);

又搞错了

写成了
student.prototype = Object.create(person());
不知道怎么想的,面试官小姐姐提示我知道Object.create怎么一回事,还口述了手写过程
Object.prototype.myCreate(proto) {
	function f() {};
	f.prototype = proto;
	return new f();
}

口述的方法倒是对的

口述之后我发现person()不对劲,又重写了
student.prototype = Object.create(person);

面试官小姐姐温柔地说,没关系,我可能太紧张了

之后是寄生组合继承
function student() {
    person.call(this);
}

student.prototype = new person();
// 或者student.prototype = Object.create(person.prototype);

我的错误跟上面的一样,

这种继承方法父类原型和子类原型是同一个对象,无法区分子类真正是由谁构造。

最后当然是最完美的寄生组合优化继承
function student() {
    person.call(this);
}

student.prototype = new person();
// 或者student.prototype = Object.create(person.prototype);
student.prototype.constructor = student;
总之错误真多,觉得没脸见人了,手写和口述讲思路难度差距真大

面试官问我知不知道防抖和节流

我回答知道,防抖在定时器定时期间再次触发,关掉旧的定时器,开始新的定时器。将多次执行变为最后一次执行,典型应用,提交按钮的点击事件。

节流在一段时间,只执行一次事件。等到这段之后再根据这段时间内由出发执行,将多次执行变成每隔一段时间执行,典型应用,拖拽事件。 我们用 leading 代表首次是否执行,trailing 代表结束后是否再执行一次

让我手写防抖,第一次手写如下
function debounce(func, wait = 1000) { let timer = null;
	return function(...args) {
		if (timer) {
			timer = null;
		}
		timer = setTimeout(func(...args), wait);
	} }
问我为什么要看到定时器把定时器赋值为null,我说要清空定时器,有没有更好的办法,我想了想说,这是一个引用类型,原先的定时器仍在内存中,可能导致内存泄露(还说错了,说成了本专业学过的频谱泄露),所以应该关闭定时器
function debounce(func, wait = 1000) {
    let timer = null;
    return function(...args) {
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(func(...args), wait);
    }
}
自己补充再重写一下手写节流吧
function throttle(func, wait = 1000) {
    let last = 0;
    return function(...args) {
        let now = +new Date();
        if ((now - last) > wait) {
            last = now;
            func(...args);
        }
    }
}
了解不了解事件循环机制,给我出了这一题
const promise1 = new Promise((resolve, reject) => {

    setTimeout(() => {
        resolve("success");
		console.log("timer1");
    }, 1000);

    console.log("promise1里的内容"); }

);

const promise2 = promise1.then(() => {
	throw new Error("error!!!");
});

console.log("promise1", promise1);
console.log("promise2", promise2);



setTimeout(() => {
    console.log("timer2");
    console.log("promise1", promise1);
    console.log("promise2", promise2); },
2000);

手写输出的顺序

promise1里的内容
promise1: Proimse{<pending>}
promise2: Proimse{<pending>}
timer1
Error: error!!!
timer2
promise1: Proimse{<fulfilled>:'success'}
promise2: Proimse{<rejected>:Error'error'} 

写完之后讲了讲思路,讲了promise是微任务,setTimeout是宏任务,事件循环机制:执行一个宏任务,执行微任务列表,经过循环再执行宏任务,再执行微任务列表。并提出老版本node循环机制不同把当前时刻宏任务、微任务执行顺序有不同

JS有哪些宏任务、微任务

宏任务setTimeout、setInterval(漏了setImmediate)

补充优先级:主代码块 > setImmediate > MessageChannel > setTimeout / setInterval

微任务包括:优先级:process.nextTick > Promise > MutationObserver

微任务提到了async、await,await后面的看作是promise.then后面的

CSS

position有哪些:

只说出来absolute、relative、fixed,不常用的背过忘了,抄一遍菜鸟上的加强记忆

描述
absolute 生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。
fixed 生成绝对定位的元素,相对于浏览器窗口进行定位。元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。
relative 生成相对定位的元素,相对于其正常位置进行定位。因此,"left:20" 会向元素的 LEFT 位置添加 20 像素。
static 默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)。
inherit 规定应该从父元素继承 position 属性的值。

提了父相子绝,被问如果父元素没有设置position:relative,子节点设置position:absolute怎么办,我说会一个个找父节点直到找到设置position:relative的,错了,应该是找到position:static以外的第一个父元素。

反问


更多模拟面试

全部评论

(5) 回帖
加载中...
话题 回帖

相关热帖

历年真题 真题热练榜 24小时
技术(软件)/信息技术类
查看全部

近期精华帖

热门推荐