个人实习面经——腾讯(CSIG)

博主目前在蚂蚁集团-体验技术部,AntV/S2 是博主所在团队的开源项目——多维交叉分析表格,欢迎使用,感谢到 S2 github 仓库点赞 star,有任何关于前端面试、就业、技术问题都可给在文章后留言。

一面( 2021/3/12):
1、自我介绍。
2、介绍一下做的可视化的项目。
3、说一下JS 中原生对象和宿主对象。
  • 原生对象的定义是:“独立于宿主环境的ECMAScript实现提供的对象”。即ECMAScript本身带有的基本对象,而不包含浏览器等宿主提供的对象。包括:Number、Srting、Date、Boolean、Object、Array、Function、RegExp、Error、TypeError、EvalError等。
  • 内置对象也是原生对象的一种,它的定义是:“由ECMAScript实现提供的,独立于宿主环境的对象,在ECMAScript开始执行时出现。”我们不需要明确实例化内置对象,它在程序开始执行时已经被实例化了,可以直接使用,目前的内置对象有:Global、Math
  • 宿主对象是ECMAScript实现的宿主环境提供的对象,宿主是指网页运行的环境,比如“操作系统”、“浏览器”,对于浏览器提供的BOM和DOM都是宿主对象。
4、JS 中的继承的方式。
  1. 原型链继承:
    重点: 新实例的原型等于父类的实例
    特点: 新实例可以继承的属性:实例构造函数的属性、父类构造函数的属性、父类原型的属性(新实例不能继承父类实例的属性)
    缺点: 新实例无法向构造函数传参;继承单一;所有新实例都会共享父类实例的属性。
function Person() {
   this.name = "gfh";
}
Person.prototype.getName = function() {
   console.log("name:", this.name);
}
function Child() {}
// 新实例的原型等于父类的实例
Child.prototype = new Person();
let child1 = new Child();
child1.getName();
  1. 借助构造函数继承
    重点: 用 call() 或 apply() 方法将父类构造函数引入子类构造函数。
    特点: 只继承了父类构造函数的属性,没有继承父类原型的属性;解决了原型链继承的缺点;可以继承多个构造函数的属性(多个 call());在子实例中可向父实例传参。
    缺点: 只能继承父类构造函数的属性(不能继承方法);无法实现构造函数的复用;每个新实例都有父类构造函数的副本,臃肿。
function Person() {
   this.name = "gfh";
   this.hobbies = ["eatting", "sleeping"];
}
Person.prototype.getName = function() {
   console.log("name:", this.name);
}
function Child(age) {
   // 通过 call() 方法将父类构造函数引入子类构造函数
   Person.call(this);
   this.age = age;
}
let child1 = new Child(24);
let child2 = new Child(25);
console.log(child1.name); // gfh
console.log(child1.age); // 24
child1.hobbies.push("coding");
console.log(child1.hobbies); // ["eatting", "sleeping", "coding"]
console.log(child2.hobbies); // ["eatting", "sleeping"]
  1. 组合继承(组合原型链继承和借用构造函数继承)(常用)
    重点: 组合了两种模式的优点,传参和复用。
    优点: 可以继承父类构造函数的属性,可以传参、可以复用;每个新实例引入的构造函数属性是私有的。
    缺点: 调用两次父类构造函数,耗内存;子类的构造函数会代替原型上的那个父类构造函数。
function Person(name) {
   this.name = name;
   this.hobbies = ["eatting", "sleeping"];
}
Person.prototype.getName = function() {
   console.log("name:", this.name);
}
function Child(name,age) {
   // 构造函数继承
   Person.call(this, name);
   this.age = age;
}
// 原型链继承
Child.prototype = new Person();
let child1 = new Child("gfh",24);
let child2 = new Child("zs",25);
console.log(child1.name, "-", child1.age); // gfh-24
console.log(child2.name, "-", child2.age); // zs-25
child1.getName();  // name:gfh
  1. 原型式继承
    重点: 用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了可以随意增添属性的实例或对象。Object.create()就是这个原理。
    优点: 类似于复制一个对象,用函数来包装。
    缺点: 所有实例都会继承原型上的属性;无法实现复用。
function CreateObj(obj) {
   function F() {}
   F.prototype = obj;
   console.log(obj.__proto__ === Object.prototype); // true
   console.log(F.prototype.constructor === Object); // true
   return new F();
}
let person = {name: "zs", friends: ["ls", "ww"]};
let p1 = CreateObj(person);
let p2 = CreateObj(person);
p1.name = "ls";
console.log(p2.name); // "zs"
p1.friends.push("zl");
console.log(person); // {name: "zs", friends: ["ls", "ww", "zl"]}
  1. 寄生式继承
    重点: 给原型式继承外套了个壳子
    优点: 没有创建自定义类型,只是套了个壳子返回对象,这个函数顺理成章就成了新对象。
    缺点: 没有用到原型,无法复用。
let person = {name: "zs", hobbies: ["eatting", "sleeping"]};
function CreateObj(obj) {
   function F() {}
   F.prototype = obj;
   return new F();
}
let p1 = CreateBoj(person);
let p2 = Object.create(person);
console.log(p1.name); // "zs"
console.log(p2.hobbies); // ["eatting", "sleeping"]
function CreateChild(obj) {
   let newobj = CreateObj(obj);
   newobj.sayName = function() {
   	console.log("name:", this.name);
   }
   return newobj;
}
let c1 = CreateChild(person);
c1.sayName(); // name: "zs"
  1. 寄生组合式继承(常用)
    重点: 修复了组合继承的问题。
function Parent(name) {
    this.name = name;
    this.hobbies = ["eatting", "sleeping"];
}
Parent.prototype.sayName = function() {
    console.log(this.name);
}
function Child(name, age) {
    Parent.call(this, name);
    this.age = age;
}
function CreateObj(obj) {
    function F() {};
    F.prototype = obj;
    return new F();
}
function prototype(child, parent) {
    let prototype = CreateObj(parent.prototype);
    prototype.constructor = child;
    child.prototype = prototype;
}
prototype(Child, Parent);
let child1 = new Child("zs", 24);
console.log(child1); // Child {name: "zs", hobbies: ["eatting", "sleeping"], age: 24}
  1. class 继承
class Parent {
   constructor() {
       this.hobbies = ["eatting", "sleeping"];
   }
   addHobbies() {
       this.hobbies.push("codding");
   }
}
class Child extends Parent {
   constructor() {
       super();
   }
}
let child1 = new Child();
child1.addHobbies();
child1.hobbies; // ["eatting", "sleeping", "codding"]
5、算法题:跳台阶(做出来了但是空间复杂度不是最优,创建了一个数组)。
6、Vue 如何注册一个全局组件,局部组件。
  1. 全局组件的注册方法:
Vue.component("组件名",{方法});

在 main.js 中引入组件,通过 Vue.component注册,如下:

Vue.component("my-component", {
template:"", // 或者使用``
data:{},
mathods: {},
// 生命周期函数等
})

在任何其他组件都可以通过<my-component></my-component>使用。一旦全局注册,即使以后不再使用这个组件,它也会随着Vue的加载而加载。

  1. 局部组件的注册:定义一个对象,包含template、data、methods等。在父组件中引入:
<template>
	<my-component></my-component>
</template>
import MyComponent from "./MyComponent.vue";
export default {
	components: {
   		MyComponent // 直接初始化
   	}
}
7、Vue 中插槽的理解。

使用场景: 在构建页面的过程中,需要把一些经常用到的公共部分抽取出来作为一个单独的组件,但在实际使用这个组件的时候,不能完全满足我们的需求,这时候需要使用插槽来分发内容。
过程: 父组件引用子组件时,希望向子组件传递模板内容,子组件让父组件传递过来的模板内容在所在的位置显示,子组件中的<slot></slot>就是插槽,可接收父组件传过来的模板内容,<slot></slot>元素自身将被替代。子组件中如果没有<slot></slot>标签,那么标签中的任何内容都会被抛弃。
作用: 可以让用户扩展组件,更好的复用组件和对其定制化处理。
分类:
3. 默认插槽
直接使用<slot></slot>
4. 具名插槽
子组件:name: “slotName”,父组件:<template v-slot: slotName></template> ,v-slot 可以使用 # 代替。
5. 作用域插槽
主要解决父组件在向子组件插槽传递模板内容时,存在访问子组件数据的问题。
参考这篇文章

8、Vue 在版本更新中,插槽有哪些变化。

vue 2.6.0之后通过 v-slot: slotName 来使用,并且 v-slot 只能添加在 <template></template> 上,和已经废弃的 slot 属性不同。

9、组件间传值的方式。
  1. props(父传子)
    父组件:<child :name="name"></child>
    子组件:
props: {
   name: {
   	type: String,
   	requird: true
   }
}
  1. this.$emit(子传父)
    子组件:
   <h1 @click="changeTitle">Title</h1>
   methods: {
   	changeTitle() {
   		this.$emit("titleChanged", "titleValue")
   	}
}

父组件:

<p @titleChanged="updateTitle">父组件</p>
methods:{
   updateTitle(e) {
   	this.title = e;
}
}
  1. 兄弟组件间传值(拥有共同父组件)
    方法:先子传父,再父传子。
  2. 任意组件间传值(包含兄弟组件)
    在 main.js 中挂载方法:
let bus  = new Vue();
Vue.prototype.bus = bus;

(子)组件A:

<button @click="sendTo">子组件一</button>
data() {
   return {
   		name: "zs"
   }
},
methods: {
   sendTo() {
       this.bus.$emit("sendTo", this.name);
   }
}

(子)组件B:

data() {
   return {
   		name: ""
   }
},
methods: {
   this.bus.$on("sendTo", params => {
   		this.name = params;
   })
}
  1. 使用 vuex

补充:父子组件方法的相互调用。

  1. 父调子
    父组件:
<button @click="useChildMethods">父组件</button>
<child ref="child"></child>
methods: {
   useChildMethods() {
   	this.$refs.child.childMethods();
   }
}

子组件:

methods: {
   childMethods() {
   		console.log("子组件的方法。");
   }
}
  1. 子调父
    子组件:
<button @click="childMethod"></button>
methods: {
   childMethods() {
   		this.$emit("parent", "childParams");
   }
}

父组件:

<child @parent="parentMethods"></child>
methods: {
   parentMethods(value) {
   		console.log("子组件传过来的参数", value);
   }
}

还可以使用 this.$parent方法。

10、Vue 和 React 的区别。
  1. 监听数据变化的原理不同。 Vue 通过 getter/setter 和一些函数的劫持,能精确知道数据的变化;而 React 默认通过比较的方式(diff)进行的,如果不进行优化,回导致大量的VDOM的重新渲染。
  2. 数据流的不同。 Vue 组件与 DOM 之间通过 v-model 双向绑定;React 一直不支持双向绑定,提倡的是单向数据流,称之为 onChange/setState() 模式。
  3. 组合不同功能的方式不同。 Vue 是通过 mixin; React 是通过HoC(高阶组件)。
  4. 组件间的通信。 在子组件向父组件传递消息的过程中,Vue 更倾向于使用事件,而 React 使用回调函数。
  5. 模板渲染的方式不同。 在表层上,模板的语法不同,React 通过 JSX 渲染模板,而 Vue 通过一种拓展的 HTML 语法渲染。在深层上,模板的原理不同,React 在组件JS代码中通过原生的JS语法实现模板中的常见语法,包括插值、循环、条件等,而 Vue 是在组件和JS代码分离的单独模板中,通过指令来实现,如:v-if。
  6. 渲染过程不同。 Vue 可以更快的计算出Virtual DOM 的差异,这是因为它在渲染过程中,会跟踪每一个组件的依赖关系,不需要重新渲染组件树;而 React 在应用状态改变时,全部子组件都会重新渲染。
  7. 框架本质不同。 Vue 是 MVVM 框架,由 MVC 发展而来;而 React 是前端组件化框架,由后端组件化发展而来。
11、Vuex 的理解。

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。state、getters、actions、mutations、modules。

12、二分法的理解(能说、举了一个二分查找的例子)。

二分法是在一个有序数组中查找目标值的方法。
步骤:

  1. 从数组的中间元素开始搜索,如果目标值等于中间元素,则搜索过程结束,否则执行下一步;
  2. 如果目标元素大于 / 小于中间值,则在大于 / 小于中间值的那一半区域中查找,然后重复步骤1中的操作;
  3. 如果某一步数组为空,则找不到目标值。
13、举出二分查找的使用场景(没举出来,面试官说了一个扑克牌排序)。
  • 查找第一个值等于给定值的元素
  • 查找最后一个值等于给定值的元素
  • 查找第一个大于等于给定值的元素
  • 查找最后一个小于等于给定值的元素

对于扑克牌排序,如果是一边摸牌一边排序整理,使用插入排序;如果是全部拿在手中了,使用快速排序

14、为什么搞前端。

研究生阶段项目需要。

15、大学生活的感受。

本科丰富,研究生项目。

16、反问。

业务。

二面( 2021/3/17):
1、自我介绍。
2、如何接触前端的。
3、HTML5新特性
4、<canvas> 中画一个矩形,如何实现鼠标放在矩形内时,矩形高亮。

通过鼠标所在的坐标来判断。

5、对前端行业的认识。
HR面(2021/3/31):
1、总结一下前面的面试情况,有什么感受。
2、自我介绍。
3、研究生,为什么选择前端呢。
4、印象最深的一个项目。
5、在项目中遇到过什么挑战。
6、自己还有哪些可以提升的地方。
7、平时怎么学习、提升自己的。
8、家庭情况。
9、人生中印象最深刻,对自己影响最大的事。
10、最想和谁合作,最不想和谁合作。
11、反问:工作节奏
12、有亲属在腾讯吗。
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值