其实前端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
这里再分享一个复习的路线:(以下体系的复习资料是我从各路大佬收集整理好的)
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
《前端开发四大模块核心知识笔记》
最后,说个题外话,我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在IT学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。
- 必选参数的接口定义
interface nullName {
firstName: string;
secondName: string;
}
function printLabel(name: nullName):nullName{
return name;
}
console.log(printLabel({
firstName:‘zhang’,
secondName: ‘san’
}))
- 需要注意的是,在传入时,如果直接传入该对象,那么则只能传入接口中所定义的参数,返回时也只能返回接口中所定义的参数;如果在传入时,先用一个对象去接受该参数,在传入时不会报错,
但是不能够被使用
- 可选参数的接口定义
interface nullName {
firstName: string;
secondName: string;
age?: number
}
function printLabel(name: nullName):string{
if(name.age){
return ${name.firstName}${name.secondName}的年龄是${name.age}
;
}else{
return ${name.firstName}${name.secondName}的年龄不知
;
}
}
console.log(printLabel({
firstName:‘zhang’,
secondName: ‘san’,
age: 14
}))
console.log(printLabel({
firstName:‘li’,
secondName: ‘si’
}))
- 函数类型接口使用
- 首先使用interface去定义接口,然后再接口内部定义所要使用的函数,需要传入的参数和其返回值是什么
interface encript {
(key: string,value: string):string;
}
const md5:encript = function(key: string, value: string):string {
return key + value;
}
console.log(md5(‘zhangsan1’,‘dsdk’));
- 可索引接口:对于数组和对象的约束
- 对于数组的约束
interface UseArr {
}
const arr:UseArr = [‘123’,‘456’];
console.log(arr)
//对于对象的约束
interface UseObj {
}
const obj:UseObj = {name: ‘zhang’,age: ‘21’};
console.log(obj);
- 类类型接口
- 使用方式:1. 首先再接口中定义方法和属性 2. 接着在用implements去实现这个接口 3. 接口中所有的方法必须在类中去实现
interface Xin{
name: string;
eat(food:string): void;
}
class Dog implements Xin {
name: string;
constructor(name: string){
this.name = name;
}
eat(){
console.log(this.name+ ‘吃饭’)
}
}
const cat = new Dog(‘小黑’);
console.log(cat.eat());
- 扩展接口
-
接口之间可以使用interface关键字来实现他们之间的继承关系
-
注意当在实现接口时,必须把接口中所有的内容都给继承,包括父接口中的参数
interface M {
eat():void;
}
interface T extends M {
work():void;
}
class Father {
name: string;
constructor(name: string) {
this.name = name;
}
code():void{
console.log(this.name + ‘写代码’);
}
}
class Son extends Father implements T {
constructor(name: string){
super(name);
}
eat(){
console.log(‘eat’);
}
work(){
console.log(‘work’);
}
}
const son = new Son(‘小河’);
son.code();
-
作用: 一个组件可以支持多种类型的数据,这样用户就可以使用自己的数据类型来创建组件
-
any类型与泛型之间的区别,any类型不能对数据类型做约束,泛型则可以对数据类型做约束
泛型函数
- 注意:泛型类中使用什么样的大写字母都可以,只是习惯上使用T,表示Type的意思
//any类型
function returnAny(value: any): any{
return value;
}
console.log(returnAny(‘ddkf’));//此时不会对类型有任何的约束
//泛型
function returnLike(value: T): T {
return value;
}
console.log(returnLike(‘123’));
console.log(returnLike(123));
泛型类
- 泛型类的定义方式,首先需要在类型去定义泛型类中,然后获得其返回值即可
class Min {
public arr: T[] = [];
add(value: T):void {
this.arr.push(value);
}
min():T {
let minValue = this.arr[0];
for(let i = 0; i < this.arr.length; i++){
if(minValue > this.arr[i]){
minValue = this.arr[i];
}
}
return minValue;
}
}
const min = new Min(); //泛型类的实例化
min.add(3);
min.add(20);
min.add(100);
console.log(min.min());
const mins = new Min();
mins.add(‘v’);
mins.add(‘a’);
mins.add(‘z’);
console.log(mins.min())
class User {
username: string | undefined;
password: string | undefined;
}
class MySqlDb {
add(info: T):boolean {
console.log(info);
return true;
}
}
const user = new User();
user.username = ‘张三’;
user.password = ‘123456’;
const db = new MySqlDb();
console.log(db.add(‘as’)); //错误,因为指定了类型
console.log(db.add(user));
class Article {
title: string;
content: string;
status: number;
constructor(title: string, content: string,status: number){
this.title = title;
this.content = content;
this.status = status;
}
}
const ar = new Article(‘张三’,‘内容’,1);
const dB = new MySqlDb
console.log(dB.add(ar));
泛型函数接口
- 泛型接口有两种定义方式:
- 第一种定义方式
interface ConfigFn {
(value: T): T;
}
var config:ConfigFn = function(value: T):T {
return value;
}
console.log(config(‘zhang’));
- 第二种定义方式
interface Config {
(value: T): T
}
function getData(value: T):T {
return value;
}
const myConfig: Config = getData;
console.log(myConfig(‘124’))
泛型 接口 以及类的操作实例
-
功能: 定义一个操作数据库的库,支持Mysql Mssql MongDb
-
要求: 所有的数据库功能一样,都有add update delete get方法
-
注意: 约束统一的规范、以及代码重构
-
解决方案:需要约束规范,所以要定义接口,需要代码重构所以需要泛型
-
接口:在面向对象的编程中,接口是一种规范的定义,它的行为和动作的规范
-
泛型:解决类 接口 方法的复用性
interface DBI {
add(info: T):boolean;
update(info: T,id: number):boolean;
delete(id:number):boolean;
get(id: number): any[];
}
//定义可以操作mysql的类
class Mysql implements DBI {
constructor(){
console.log(‘数据库建立’);
}
add(info: T):boolean {
console.log(info)
return true;
}
update(info: T, id: number): boolean {
throw new Error(“Method not implemented.”);
}
delete(id: number): boolean {
throw new Error(“Method not implemented.”);
}
get(id: number): any[] {
throw new Error(“Method not implemented.”);
}
}
class Mssql implements DBI {
constructor(){
console.log(‘数据库建立’);
}
add(info: T):boolean {
console.log(info)
return true;
}
update(info: T, id: number): boolean {
throw new Error(“Method not implemented.”);
}
delete(id: number): boolean {
throw new Error(“Method not implemented.”);
}
get(id: number): any[] {
throw new Error(“Method not implemented.”);
}
}
class User {
username: string | undefined;
password: string | undefined;
}
const user = new User();
user.password=‘123’;
user.username = ‘张三’;
const mysql = new Mysql();
console.log(mysql.add(user))
模块化
-
模块:文件之间的引用方式就叫做模块,侧重于代码的复用
-
命名空间:内部模块,主要用于组织代码,避免命名冲突
- 命名空间的实例
namespace A {
interface Animal {
name: string;
eat():void;
}
export class Dog implements Animal {
name: string;
constructor(name: string){
this.name = name;
}
eat(){
console.log(this.name + ‘吃饭’)
}
}
export class Cat implements Animal {
name: string;
constructor(name: string){
this.name = name;
}
eat(){
console.log(this.name + ‘在唱歌’)
}
}
}
const dog = new A.Dog(‘小狗’);
console.log(dog.eat());
const cat = new A.Cat(‘小猫’);
console.log(cat.eat())
装饰器
-
注意:在当前的版本中需要在ts.config中设置experimentalDecorators为true
-
含义: 装饰器是一种特殊类型的声明,能够被附加到类声明,方法,函数或参数上,可以修改类的行为
-
通俗理解: 装饰器是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、参数的功能
-
常见的装饰器:类装饰器、属性装饰器、方法装饰器、参数装饰器
-
装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可以传递参数)
- 类装饰器:装饰器在类声明之前被声明(仅靠着类声明),装饰器应用于类构造函数,可以用来间是,修改或者替换类
//1. 普通装饰器
function logClass(params: any){
console.log(params);
//params表示的就是当前类
params.prototype.appUrl = “动态扩展属性”
}
@logClass
class HttpClient {
constructor(){};
getData(){}
}
const http:any = new HttpClient();
console.log(http.appUrl)
//装饰器工厂:可以传递参数
function logClass(params: any){
return function(target: any){
console.log(target,params);
//此时额target指的是类,params指的是装饰器中传入的参数
}
}
@logClass(‘hello’)
class HttpClient {
constructor(){};
getData(){}
}
const http:any = new HttpClient();
console.log(http.appUrl)
-
类装饰器重构构造函数的例子
-
描述: 类装饰器表达式会在运行时当作函数被调用,类的构造函数作为唯一的参数,如果类装饰器返回一个值,他会使用提供的构造函数来替换类的声明
function logClass(params: any){
console.log(params);
return class extends params {
appUrl: any = ‘我是修改后的数据’
getData(){
this.apiUrl = this.appUrl+ ‘—’;
console.log(this.appUrl);
}
}
}
@logClass
class HttpClient {
public apiUrl: string | undefined;
constructor(){
this.apiUrl = “我是构造函数里得apiUrl”
};
getData(){
console.log(this.apiUrl);
}
}
const http:any = new HttpClient();
http.getData()
-
属性装饰器:属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数
-
对于静态成员来说是类的构造函数,对于实例陈成员是类的原型对象
-
成员的名字
function logClass(params: any){
return function(target: any) {
}
}
function logProperty(params: any){
return function(target: any, attr: any){
console.log(target, attr);
target[attr] = params;
}
}
@logClass(‘xxx’)
class HttpClient {
@logProperty(‘abs’)
public apiUrl: string | undefined;
constructor(){};
getData(){
console.log(this.apiUrl);
}
}
const http:any = new HttpClient();
http.getData()
-
方法装饰器:会被应用到方法的属性描述符上,可以用来监视,修改或者是替换方法的定义,方法装饰会在运行时传入下列的3个参数
-
对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
-
成员的名字
-
成员的属性描述符
//方法装饰器一
function get(params: any){
return function(target: any, methodName: any, desc: any){
console.log(target);
console.log(methodName);
console.log(desc);
target.appUrl = “xxxx”;
target.run = function(){
console.log(‘run’)
}
}
}
class HttpClient {
public url: any;
constructor(){}
@get(‘http://www.baidu.com’)
getData(){
console.log(this.url);
}
}
const http:any = new HttpClient();
console.log(http.appUrl);
http.run();
//方法装饰器二,覆盖掉原本对象上的方法
function get(params: any){
return function(target: any, methodName: any, desc: any){
console.log(target);
console.log(methodName);
console.log(desc);
//修改方法装饰器中的方法,把装饰器方法传入的所有参数修改为string
//1. 保存当前的方法
const oMethod = desc.value;
desc.value = function(…args: any[]){
args = args.map(item => String(item));
console.log(args);
}
}
}
class HttpClient {
public url: any;
constructor(){}
@get(‘http://www.baidu.com’)
getData(){
console.log(“这是构造函数中的getData”);
}
}
const http:any = new HttpClient();
http.getData(‘string’,123);
//方法装饰器三,在原本的方法上变更该方法
function get(params: any){
return function(target: any, methodName: any, desc: any){
console.log(target);
console.log(methodName);
console.log(desc);
//修改方法装饰器中的方法,把装饰器方法传入的所有参数修改为string
//1. 保存当前的方法
const oMethod = desc.value;
desc.value = function(…args: any[]){
args = args.map(item => String(item));
console.log(args);
oMethod.apply(this,args);
}
}
}
class HttpClient {
public url: any;
constructor(){}
@get(‘http://www.baidu.com’)
getData(){
console.log(“这是构造函数中的getData”);
}
}
const http:any = new HttpClient();
http.getData(‘string’,123);
-
方法参数装饰器:会在运行时当作函数被调用,可以使用方法参数装饰器为类的原型,增加一些元素数据,传入下列3个参数
-
对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
-
方法的名字
-
参数在函数列表中的索引
function logParams(params: any){
return function(target: any, methodName: any, desc: any){
console.log(target);
console.log(methodName);
console.log(desc);
target.apiUrl = params;
}
}
class HttpClient {
public url: any;
constructor(){}
getData(@logParams(“xxxx”) uuid: any){
console.log(uuid);
}
}
const http:any = new HttpClient();
http.getData(‘123456’);
console.log(http.apiUrl)
- 装饰器之间的顺序: 属性 》 方法 》 方法参数 》 类 ,如果同时存在就是从后往前
ES6
-
列举常用的ES6特性:
-
箭头函数需要注意哪些地方?
-
let、const、var
-
拓展:var方式定义的变量有什么样的bug?
-
Set数据结构
-
拓展:数组去重的方法
-
箭头函数this的指向。
-
手写ES6 class继承。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
微信小程序
-
简单描述一下微信小程序的相关文件类型?
-
你是怎么封装微信小程序的数据请求?
-
有哪些参数传值的方法?
-
你使用过哪些方法,来提高微信小程序的应用速度?
-
小程序和原生App哪个好?
-
简述微信小程序原理?
-
分析微信小程序的优劣势
-
怎么解决小程序的异步请求问题?
其他知识点面试
-
webpack的原理
-
webpack的loader和plugin的区别?
-
怎么使用webpack对项目进行优化?
-
防抖、节流
-
浏览器的缓存机制
-
描述一下二叉树, 并说明二叉树的几种遍历方式?
-
项目类问题
-
笔试编程题:
最后
技术栈比较搭,基本用过的东西都是一模一样的。快手终面喜欢问智力题,校招也是终面问智力题,大家要准备一下一些经典智力题。如果排列组合、概率论这些基础忘了,建议回去补一下。