前端笔面经(下)

JS

・全称Javascript,是面向对象的、解释型的语言
——C、Lua是面向过程的语言,C#、JS、Java、Python是面向对象的语言,C++二者兼有
——C、C++、C#是编译型语言,JS、Python是解释型语言,Java介于两者之间
原始数据类型:null、undefined、Boolean、Number、String、BigInt、Symbol
引用数据类型:Object(万物起源)、Array、Map、Set、Function/Date/RegExp(显示为字符串)、Error、Promise、WeakMap、WeakSet……
・和Java的不同之处:
——Java是静态类型的、面向对象的编程语言,声明变量要规定类型,JS是动态类型的解释型脚本语言,声明变量不用规定类型(TS也可规定)
——Java在JVM虚拟机上跨平台运行,JS通常只能在浏览器或nodejs中运行
——Java可以创建多线程处理并发任务,JS则使用异步方式处理并发任务
作用域:指变量与函数的可访问范围,由当前环境与上层环境的一系列变量对象组成
——全局作用域:代码在程序的任何地方都能被访问,window对象的内置属性都拥有全局作用域
——函数作用域:在固定的代码片段才能被访问
——作用域链:若该范围没有查到某变量,则会向外一层层查找
・属于ES6引入的新特性:Symbol/Set/Map、用let和const声明、箭头函数、模板字符串、解构赋值、类、 异步编程、模块导入与导出……
**运行原理:**浏览器在HTML中遇到script标签时就会解析并执行脚本,解析时会被解释器解析并被编译器即时编译
——执行主线程,同时使用事件循环机制处理异步事件
——运行时还会使用标记清除和引用计数等方式回收垃圾

关键字

・分支:if、else、switch、case
・循环:do、for、while
——JS可以用for(var/let xxx in/of xxx)循环语句
・跳转:break、continue、return
・单独的this是全局对象(浏览器中指Window window),类里的this是类实例,元素事件中的this指向接收事件的元素
・方法里的this是存储它的对象,若在最外层写函数,那它的this就是window
typeof 变量查基本数据类型,返回小写字符串,遇null和引用数据类型则输出"object";变量 instanceof 类名查引用数据类型
・void返回空值,但后面跟的括号语句要执行
・其它:debugger、default、finally、with

语法

・行尾分号可以不写,但最好还是写
・//是单行注释/*…*/是多行注释
・若用逗号连接了多个表达式,虽然每个都会执行,但只有最后一个表达式被返回
・++/–符号符合谭浩强运算律,即放变量前就先加,放后面就后加;**是幂
・两(不)等号比较前会作类型转换,三(不)等号比较前不转换
・比较符号不能连比,即1<2<3会先变成true<3,再强制转换为1<3,最后变成true
・0,‘’,[],false在双等号下相等,null和undefined在双等号下相等,但两组之间在双等号下不相等
・但若使用布尔转换,有引用的[]和{}会转换为true,而0、‘’、null、undefined、NaN会转换成false
・双逻辑运算符(如&&)运算符返回的是能(在短路特性下)决定结果的那一边的表达式的值(而非布尔值),决定结果靠的是“隐式的布尔转换”
・问号不仅可用于三目运算(exp ? yes : no),还能保变量(a??b ⇔ a !== undefined ? a : b)和保属性(a?.b ⇔ a.b ? a.b : undefined)
・三点可用于解构数组或对象,如[…a,…b]⇔a.concat(b);用于对象、集合、映射等也可缝合
——对象的解构为{…obj1, …obj2}
——映射的解构为new Map([…map1, …map2])
——集合的解构为new Set([…a, …b])
——解构元素时若键有重复,则后解构的值会代替先解构的

声明

・声明变量是const、let、var,新类是class,新函数是function,新引用变量实例是new
・var变量会成为所在对象的键值对,且var在同一块中可重复声明同名变量,let和const不行
・var具有函数级作用域,let和const具有块级作用域
・变量提升:若之前没有定义x,var x=1的var x会自动提到前面,但x=1不会跟着走;let和const不会提升
・声明const变量时必须初始化值且不能更改,但该变量内的属性可以改

内置函数

・内置函数“内置”在全局变量中
・console.log():在控制台输出
——console表示控制台,也有debug、error、info、warn等输出样式
・eval():可以剥一层引号并直接运算字符串的内容,严格模式不可用
・open(site, *name)用于打开网页,
・parseInt()和parseFloat()用于类型转换
・setTimeout(f,t,argi…)在t毫秒后调用f函数,argi代表传给f的参数,属于异步线程宏任务
・a=setInterval(f,t,argi…)是每隔t毫秒调用f函数,需要调用clearInterval(a)才能停止
・setImmediate(f)在宏任务开始时立即执行

异常处理

・形如try{…} catch(e){…},(e)可省略
・throw new Error(“err”)可以强行出错,该错误的字符串等同于"Error: err"

事件循环机制(Eventloop)

・JS是单线程的,在代码中遇到同步任务会放进主线程栈中,完成后再取出
・在把该次循环内的同一种任务都一边收集一边解决完后,才会再继续下下一种任务或下一循环
・遇到异步任务则会先放进任务队列,待同步任务处理完后再依次入栈运行,所以代码块中同步代码先运行,异步代码后运行
・异步任务又分为宏任务和微任务,I/O、定时器、事件绑定、ajax等属于宏任务,而Promise和process.nextTick等属于微任务
・微任务优先级又比宏任务高,因此在同一代码块中Promise先运行而setTimeout后运行

内存分配与垃圾回收

・内存分配:
——栈内存:变量线性有序地存储,容量小,系统分配效率高
——堆内存:首先要在堆内存新分配存储区域,之后又把指针存储到栈内存中,效率相对低一些
・垃圾回收机制:
——栈内存:变量用完就会回收,存取速度较快,并且栈内存中的数据可以共享
——堆内存:堆内存中的对象不会随方法的结束而销毁,就算方法结束了,这个对象也可能会被其他引用变量所引用(参数传递)
——对象创建后会被反复利用,因为对象的创建成本通常较大,且会被保存到运行时数据区(堆内存)
——只有当系统核实没有任何变量引用某对象时,系统才会回收它
・容易造成内存泄漏的情况:
——意外的全局变量:使用未声明的变量可能会意外地创建一个全局变量,使之一直存留在内存中无法回收
——被遗忘的计时器与回调函数:若定时器的回调函数仍然可调用,或其内引用了外部变量,那它会一直留在内存中无法被回收
——脱离DOM的引用:即使DOM被删除了,只要它还被引用就无法被回收
——闭包:见函数部分

基本变量类型

・boolean、number、string、null、undefined、bigint、symbol

BigInt 大整数

・笔试时若数据规模过大可使用它来运算
・数字加后缀n即为bigint
・bigint只能和同类型变量计算,不能和Number混用

Number 数字

・包括整数、小数、±Infinity和NaN
・前缀0b/0B二进制,0/0o/0O八进制(0开头出现8和9变回十进制),0x/0X十六进制
・后缀e/E为科学计数法,n为bigint
・Infinity代表正无穷,Infinity+Inifinity等同号运算得到的仍为Infinity,Infinity-Infinity等未定式得到的是NaN,-Infinity同理
——同号Infinity之间相等
・NaN和任何数运算都会产生NaN,和任何式子比较都是false
・isInteger()检测整数,isFinite()和isNaN()用于检测同为数字的±Infinity和NaN
——isInteger(Infinity)和isFinite(NaN)也是false

String 字符串

.length用于获取长度
・s.charAt(i)和s[i]都可用于索引
・s.charCodeAt()将字符变Unicode,String.fromCharCode()将Unicode变回字符(串)
・concat()或加号:连接多个字符串,遇number等会将其强制转换成字符串,数组同理
・indexOf()左搜索,lastIndexOf()右搜索,搜不到则返回-1,数组同理
・s1.localeCompare(s2)和比较符号可以按字典顺序比较字符串大小,前者可调语言并输出-1/0/1
・match(regExp)是求所有与正则表达式匹配的子字符串,replace(regExp, s)是依次替换它们,search(regExp)只返回首个匹配索引
・repeat(n)为复读字符串
・split(*char)可切字符串为数组,反过来join(*char)可粘数组为字符串
・startsWith()判开头,endsWith()判结尾,includes()判子串
・substr(a, *n)和slice/substring(a, *b)可切片,前者可加长度,后者可加上限,slice加负索引表倒数
・众所周知,切片包含索引上限而不包含下限
・toLowerCase()全小写,toUpperCase()全大写,to后加Locale表示考虑语言环境
・trim():移除字符串首尾空白
・abc`${123}`是模版字符串,里面的表达式可以被解析

Symbol

・纯Symbol(…)只能用于产生一个独一无二的“符号”
Symbol.iterator可用于为对象添加迭代器,它可以使自定义类的变量可用for-of循环遍历
・迭代器由对象中的方法Symbol.iterator{…}定义
・该方法要返回一个含next()方法的对象,它在每步迭代被调用
・next方法又要在每步迭代之后返回对象{value:…, done:…},其代表该步迭代的返回值和迭代是否完成
・迭代器方法通常写成下式,this代表迭代器所在的对象,this.data则是被迭代的数据:

[Symbol.iterator](){  
	let index = 0;
    return {
    	next(){
      		value: this.data[this.index++], 
      		done: this.index < this.data.length
      	}  
	};  
}  

引用变量类型

类名.constructor:类的构造函数,任何变量都有
——类名本身也是类构造函数
——构造函数的name是类名字符串
类名.prototype:以对象的形式暴露该类的定义,使类的定义能被修改,但其类型=类名
——改变prototype里的属性不会对该类已创建的实例的该属性产生影响
类实例.proto=类名.prototype
——类名.prototype.__proto__是父类的prototype
——大多数类的父类是Object,Object无父类,所以Object.prototype.__proto__是null
・类名本身也代表该类的构造函数,如Object==Object.prototype.constructor是true
・extends在class后置表继承
・function本身也可以用来定义类,甚至还能使用this,但那样就继承不了
・给类中的属性/方法前加#号表私有

Object 对象

万物皆对象,虽然Null类有null,Undefined类有且仅有undefined,但这两个类却用不了
・浏览器控制台中万物皆储存在全局对象“Window window”中
・其键只能是string或者symbol
.length用于获取键的数量
属性描述符包括value(值)、configurable(键可变)、enumerable(可枚举)、writable(值可变)、get(获取回调)和set(设置回调)
・**Object.assign(obj, obj1, obj2, …)**会依次将obj1、obj2、……中有而obj中一开始没有的键的值赋到obj中,返回的是新对象
・**Object.create(obj, *描)**是浅拷贝,后可跟描述符配置对象
——若有B.prototype=Object.create(A.prototype),B便继承了A的属性和方法
・Object.defineProperty(obj, 属性, 描述符)可以更改属性描述符,也在Vue中用于监听变量的变化
——其中的get和set方法可以读写属性
——Object.defineProperties()可以一次更改多个属性描述符
・Object.freeze():冻结对象,使之完全不可变,动了不报错
・Object.seal():封存对象,使之键不可变但值可变
——Object.isFreeze/isSealed()可判断对象是否被冻结/封存
・Object.fromEntries():将二维数组变回对象
Object.entries()列出键值对,Object.keys()列出键,Object.values()列出值
・Object.getOwnPropertyDescriptor(obj,属性):获取obj的某属性的描述符
——Object.getOwnPropertyDescriptors(obj)获取所有属性的描述符
・in递归/判断有无键,of递归值,delete删除键
・声明的变量=this中的键值对,所以可以用delete删掉声明的变量
・hasOwnProperty(key):有无某键
・isPrototypeOf(object):对象是否在object的原型链上
・toString():将各种变量硬转成字符串,数组套娃会被展平,对象硬整会变成’[object Object]’
・valueOf():返回对象的基本类型(原始类型+object)值
・obj.key, obj[key], obj.valueOf(key)都可索引
・即使引用变量的内容一样也不相等,因为引用不相等
・对象里值为函数的键值对可以写成a: function(){}、a:()=>{},甚至可直接写a(){}

Array 数组

.length用于获取元素数量
unshift(…)首入,shift()首出,push(…)尾入,pop()尾出;一次可入多个元素,入后返回数组长度,出后返回被出元素
・every(f)和some(f)判断是否所有/存在元素满足要求
・**filter(f)**是新筛选数组,**map(f)**是新映射数组
・find(f)是寻找首个符合要求的元素,findIndex(f)是找find(f)的索引,findLastIndex(f)从右往左找
・forEach((item, *index, *arr)=>{…}:遍历元素,可以当for循环使
——forEach、map、filter、some、every都可以传入这三个参数
・Array.from()可将Map展成二维数组
・**includes()**判断有无某元素
・reduce(f, *init)是累次计算,reduceRight(f, *init)是从右往左;如.reduce((a, b)=>a+b)是求和
・**reverse()**是反转
splice(a,n,*item1,*item2,…):从第a个元素开始拿掉n个元素,然后可以从该处再添加若干元素
・**sort((a, b)=>f(a,b))**用于排序,若f(a-b)<0则a排在前,反之a排在后
・JS数组可以像python元组那样用于解构赋值,形如let [a,b,c]=[1,2,3],其效率高于concat等方法
・直接delete键或不按顺序给数组赋值会造成数组空值
——遍历键遍历不到,遍历值或键值对时得到undefined

Date 日期

・包含年月日时分秒毫(fullYear/month/date/hours/minutes/seconds/milliseconds)
・getDate()是获取日期,其它同理,设置就改成set;加上UTC表示世界时,如getUTCDate()
・可以用比较符号比较日期先后,先小后大

EventSource

・EventSource用于接收Server-Sent事件通知

Function 函数

・用function声明,也可以写成箭头函数(≈匿名函数)
・函数也可以提升,但仅限于function f(){}型函数而非f=function(){}或f=()=>{}型函数
・函数不加return或return后不加语句,则会返回undefined
・参数加等号即为设置默认值;参数为{name, age=1}即为关键词参数,传入对象以设置相应值
闭包在JS中即为函数的作用域
——闭包内可以定义和使用私有方法和变量,其不会暴露到外部,保证了数据的安全性
——闭包内的脚本可以引用闭包外的参数和变量,因此函数即可一层层嵌套使用
——闭包中的参数和变量(如监听器)不会被垃圾回收机制回收,因此会增加内存使用量,使用不当可能造成内存泄漏
・短的箭头函数若右侧只有一个表达式,不加花括号即返回表达式的值,加了要写return才能返回
——箭头函数的特点是写法简洁,省略花括号可直接返回表达式的值
——箭头函数中的this等于其外层的this
——箭头函数中的arguments也等于其外层函数的arguments,若确实需要参数列表,只能将参数写成解构式
——箭头函数不能用于构建新类
・void前置代表无返回值,void+表达式等同于“表达式; return;”
・一般函数同步,加async后也可异步执行其中await后的内容
——async-await语句是生成函数*-yield的语法糖
——async内await行及其以前的内容是同步执行的
——await x; y可以看做new Promise(()=>x).then(y)
——await后的内容要在await行的内容计算完后的下一循环的微任务中才执行
——若await跟的是一个含then方法的对象,则会把它看做Promise并调用then方法
——若await之后出现reject,则会运行并跳出async函数
・f.call(obj, *arg1, *arg2, …)等同于f(arg1, arg2, …),它在调用函数f的同时将f内部的this暂时改成了obj
——call之后,参数中的this不会被改成obj
——apply与call类似,但参数是以列表形式传入
——bind与call类似,但它并非直接调用函数,而是返回改变this后的新函数
・函数的属性name储存了函数名,匿名函数的名字是空字符串
・函数的属性caller则指向调用它的对象
・函数体内也带有属性arguments
——arguments里将传入函数的多个参数存储为列表/对象,这样即可处理可变参数列表
——arguments.length为传入参数的个数
——参数即使有默认值,没从外面传入的话arguments里也不会有
——arguments只记录了函数初始传入值,改变arguments也会改变函数参数,但改变函数参数不影响arguments
——参数若为关键词参数,传入函数的参数是对象,arguments里便只有该对象一个元素
——arguments.callee等于函数本身,可用于匿名函数的自指
・严格模式下callee和caller都不可用
・function* f(){…}可以用于定义生成函数,常用于定义生成器函数或协程
——令g=f()可得到生成器
——生成函数体内加yield代表返回并暂停,调用g.next()继续执行,返回值为g.next().value
——生成函数体内加return代表返回并结束,g.next().done代表函数是否结束
・函数科里化(Currying)是指将多参数函数变成单参函数串联的形式,若函数f(a,b)被科里化函数包装成函数F,那么有f(a,b)==F(a)(b)
——实现方式形如function curry(f){return function(a){return function(b){return f(a,b)}}}
——结合arguments及其length参数,可以包装出任意长的科里化函数

JSON

・JSON.stringify(obj, *map, *space)可以把基本数据类型、数组、对象等变量转换成字符串
——它会忽略值为undefined的属性
——它不能格式化有循环引用的对象
——replacer可以是一个数组,用于指定哪些键需要被格式化;也可以是一个用于映射的函数(key, value)=>{…}
——space是每行缩进空格数,设置之后输出的字符串会自动换行
・JSON.parse(obj, *map)可以将JSON变回对象,map是和上文同理的映射函数

Map和Set

・**Map(映射)**实例的键可以是任意类型,其打印出来为Map(n){键=>值,键=>值…}
——add()是为集合添加元素
——Map和Set的size属性为键值对/元素的数量
——set(键, 值)设置键值对,get(键)求值,has(键)求有无键/元
——若键为基本变量类型,那么只要变量值相等就算同一个键(集合的元素同理)
——delete(键)删除键/元素,clear()清空键值对/集合
——entries()获取所有键值对/值值对,keys()获取所有键,values()获取所有值/元素,但返回的是MapIterator/SetIterator
——用[…map.entries()]可以将map解析为二维数组
・Map的键有顺序,先设的排在前
・new Map([[键, 值], [键, 值]…])可以把二维数组转换为Map
・**Set(集合)**没有键,其打印出来为Set(n){元素,元素…}
——intersection()求交集,union()求并集,difference()求差集
——并集也可写作new Set([…a, …b])
——交集也可写作new Set([…a].filter(x=>b.has(x))),差集则是!has
Map和Set可用forEach迭代,而WeakMap和WeakSet不可迭代,且后两者的键值对若不被引用就会被自动回收
・WeakSet的元素和WeakMap的键都必须是引用变量

Promise

・js只有一个线程在“同步运行”,要实现多个线程运行的效果就要写异步运行函数
・若需将多个异步事件串联在一起,用setTimeout写需要层层嵌套写回调函数,史称“回调地狱”
・因此,神降下了Promise对象以串联多个异步事件
・它只有三种状态:pending(进行中),fulfilled(接受),rejected(拒绝)
召唤Promise的格式为new Promise(function(resolve, reject){…}).then(res=>{…}).catch(err=>{…})
——可以调用Promise.resolve/reject()来主动接受或拒绝,但返回值为Promise对象的实例
——在Promise中直接写Promise(resolve(…); reject(…)),它会因为“resolve/reject未定义”而直接在编译时报错
——
・Promise里的语句运行完后会跳入首catch前的首then,运行出错则会跳入首catch
・在Promise中使用resolve(res)则会将res带上并跳入首catch前的首then,使用reject(err)则会将err带上并跳入首catch
・无论接受还是拒绝,如果后面跟了finally都会执行,但它不接受参数;它返回新的Promise,使事件链得以继续执行
・Promise后面可以链式连接多个then、catch、finally并以此执行
・Promise.all([p1, p2, p3, …]).then(…).catch(…)在数组中各Promise完成后才执行,若其中无Promise、有拒绝或报错的则跳入catch
——若某一项不是Promise实例,则会被强制转换成Promise实例
——any与之类似,但只要有一个成了就直接走流程
——race也类似,但只要有一个接受或拒绝,就将其结果作为整个Promise的结果并走后续流程
Promise.allSettled传入的是一个数组,当数组中的元素全部处理完后返回依次列出各元素处理结果的数组
・异步:加async修饰函数、加await修饰异步表达式

RegExp 正则表达式

・正则变量的写法形如/[a-zA-z]+://[^\s]*/g,头尾必须用撇括住正则表达式
・尾i为大小写混用,尾m为多行匹配,尾g为全局匹配(不加就只匹配第一个)
・\n为换行符,.为除换行符以外的任意字符
・^代表在字符串开头,$代表在字符串结尾
・\为转义,匹配符号时有意义的符号前必须加捺
・\d为数字,\w为数字和字母,\s为空格,大写(\D,\W,\S)为除该种字符以外的任意字符
・\uxxxx代表Unicode字符,如[\u4e00-\u9fa5]代表任一汉字
・方括号[abc]代表匹配括号中的任一字母
・方括号中加a-z代表abcd…xyz,上下限可以改,数字同理
・a|b|c|…代表并联匹配其中任一表达式,要跟其它式子串联就要加圆括号
・?后置代表匹配0~1次,+后置代表匹配至少一次,*后置代表可匹配任意次(也可无)
・{n}代表匹配n次,{n,}代表至少匹配n次,{m,n}代表匹配m~n次
・小括号可以用于并联或循环式
・a(?=b)代表匹配后面跟着b的a
・a(?!b)代表匹配后面不是b的a。

通信相关库

AJAX(XMLHttpRequest)

・AJAX全称为Asynchronous JavaScript and XML,是一种通过在后台与服务器异步交换数据,在不干扰用户当前操作或重新加载页面的情况下更新部分网页内容的技术
・AJAX通过XMLHttpRequest对象与服务器交换数据(后文设该对象的实例为xhr)
・open(方法,URL,异步):用于配置请求,其参数依次请求方法(如"GET"、“POST”)、地址以及是否异步处理请求
・send(内容):发送请求到服务器,一般发GET请求时不用填内容
・abort():强行停止请求,且状态会变回0
・请求发送到服务器之后,需要处理来自服务器的响应,若请求状态(xhr.readyState)改变则会触发xml.onreadystatechange事件
——初始请求状态为0
——调用open()方法变成1
——调用send()方法并接收到响应头信息后变成2
——响应体正在被接收(尚未完成)时为3
——请求已完成且响应已就绪后为4
・若请求状态改变时有xhr.readyState == 4 && xhr.status == 200(xhr.status代表状态码),则请求成功,服务器返回的数据为xhr.responseText

Fetch

・fetch也是Web API的内置函数,它是Ajax的替代品, 其使用Promise提供了更简洁的语法,使得异步处理变得更加简洁明了
・其用法如下:

fetch(url, *options).then(response => {   // 处理响应   
    if (!response.ok) {
        throw new Error('Network response was not ok');  
    }  
    return response.json(); // 解析 JSON 数据  
  })  
  .then(data => {// 处理数据})  
  .catch(error => {// 处理错误});

・配置options可包含方法(method,如GET或POST)、请求头(headers)、请求体(body)、模式(mode,如cors、no-cors、same-origin)、凭证(credentials)等
・response.ok用于检测响应是否成功
・fetch不会自动处理JSON 数据,需调用response.json()来解析JSON格式的响应体
・fetch默认不发送或接收cookies,除非在credentials里配置
・abort():强行停止请求

Axios

・Axios是一个将原生XMLHttpRequest封装后再用Promise实现的HTTP请求库
・它和fetch都是基于Promise实现的,所以都可用async/await写
・axios.get(url)用于GET,axios.post(url)用于POST
・拦截器可以在then之前执行动作
——请求拦截器是axios.interceptors.request.use((request)=>{…}, (error)=>{…});
——响应拦截器是axios.interceptors.response.use((response)=>{…}, (error)=>{…});
——即使有拦截器,程序也会继续走到then或catch
・停止axios的方法:
——先设置const source = axios.CancelToken.source();
——然后再在url后的第二个参数设置cancelToken: source.token
——最后调用source.cancel()停止请求
・常问点:为什么选用axios,fetch和axios的区别?

TS

・是JS的超集,JS有的TS都能使,反过来不一定
・声明变量时可以写作“var x: number”以规定其类型
——类型默认是any,代表任意类型皆可,但在赋值后坍缩;never代表都不可,只接受出错
——变量也可是多种类型/联合类型,形如var x: number | string
——此时只能调这些类型的共有属性或方法,若赋值则它坍缩回一种类型
——函数的类型声明形如function f(…): number{…}
——数组的类型声明形如:number[]或泛型声明Array<number>,其元素类型必须一致
・TS中若数组元素类型不同,那它将变为“元组”
——元组的声明方式形如:[number, number],以这种方式声明的变量皆为元组
——元组声明后也可添加元素,但其类型只能是已有类型的联合类型(除非声明变量为any)
——给整个元组型变量赋值时需提供所有项
・函数型变量的声明形式如(string)=>number
——也可以将函数、接口或类的变量类型声明为“泛型T”
——这样既能通过编译,又能提高可读性,它不用预先指定具体类型,在使用时程序自动指定类型
接口interface:类似struct,可以声明有值或抽象的属性/方法,但新建变量时属性和方法的类型必须和声明里的匹配,如:
interface A {
a?: string,
b: “114514”,
c: () => string
[d: string]: number
}
——后续即可定义该类变量var a:A = {…},但赋值的类型必须一一对应
——加问号的属性代表可有可无,加方括号的属性代表可任意添加类似属性
——属性名前加readonly为只读
——接口可用extends关键字继承多个其它接口或类
——类可用implements关键字继承多个其它接口,但必须实现抽象方法

枚举类型形如enum A={a, b=2, c},用于将某种设定绑定为常数
——第一个元素默认是0,也可给属性赋值,没赋值的属性的数值=前一元素的值+1
——但若给元素设了非number值,就必须给所有元素都赋值
・类型断言:用<number>a强行让编译器认为a是number, <number><any>a强行让编译器认为a是number或any

nodejs模块

・process:在nodejs中保存和当前进程相关的消息
——process.nextTick类似于Promise,可以调用异步线程的微任务
——.versions保存当前node和依赖库的版本

Vue与设计模式

MVC(Model-View-Controller)设计模式
——使用场景:需要将数据、业务逻辑和界面显示分离,以便于独立开发和维护
——关系:C→M↔V↔C
——Model:代表一个存取数据的对象,它也可以带有逻辑,在数据变化时更新Controller
——View:将Model中包含的数据可视化
——Controller:接收用户的输入,会反作用于模型和视图,它控制数据流向Model,并在数据变化时更新View,并分离开View与Model
——优点:解决了应用程序中业务逻辑、数据和界面显示的耦合问题,使得开发和维护更加清晰和简单
——缺点:因为耦合性高,所以可读性、健壮性、可拓展性较低,不便于测试
MVP(Model-View-Presenter)设计模式
——关系:V↔P↔M
——Model充当数据库,View是交互界面;Presenter分开两者,从M读写数据,调用V的逻辑接口并将结果返回V
——其特点是将View与Model解耦,各部分分工明确,使各个单元易于维护、测试和扩展
Vue是一个典型的MVVM(Model-View-Viewmodel)设计模式下的框架
——关系:V↔Vm↔M
——模型(Model)代表数据及相关逻辑,视图(View)即为用户界面
——视图模型(Viewmodel)是Model和View之间的桥梁,它与M和V绑定,即可以监听M的变化与相应的数据,也可以处理V的交互事件,并向V展示数据
・Vue的原理:
——Observer(数据监听器):其核心是通过Object.defineProperty()来监听数据的变动,其内部可以定义setter和getter,数据发生变化就会触发setter,这时候Observer会通知订阅者Watcher
——Compiler(指令解析器) : Compile主要做的事情是解析模板指令,将模板中变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加鉴定数据的订阅者;数据有变动时就会收到通知,然后更新视图
——Watcher(订阅者) : 是Observer和Compile的通信桥梁,主要是在自身实例化时往属性订阅器(Dep)里面添加自己,自身必须有一个update()方法;待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调
——MVVM整合前三者并作为数据绑定的入口,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令(vue中是用来解析{{}}),最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化→视图更新;视图交互变化(input) →数据model变更的双向绑定效果
——Vue的双向数据绑定是通过Object.defineProperty()的数据劫持结合发布订阅模式来实现的,其中数据和视图同步,数据发生变化时视图跟着变化,视图变化时数据也随之发生改变
・为什么选择用Vue,与React等框架相比有什么特色?(非Vue技术栈企业)

其它

・import导入库和组件
・export导出该组件
——components放导入组件,data函数的返回值放属性,methods放方法
——data设计成方法一是为了方便复用,二是为了区分开同一组件的不同实例的相同属性
——computed放计算属性,get函数读取属性值,set函数设置属性值
——setup放初始脚本,mounted方法放加载后脚本,类似方法又称选项式API
・组件的生命周期包含create(创建)、mount(挂载到DOM节点)、update(重新渲染和更新)和destroy(卸载和销毁)
——加before-为前钩,加-ed为后钩
・将文件用来导出组件的代码为<script> export default{data() {return {a:1, b:2}}} </script>
组合式API是指将mounted等方法直接从APP对象或组件导出对象挪到setup里用现成的onMounted()方法
・Vue的路由有默认的hash路由和history两种路由模式
——前者通过监听onhashchange事件处理URL的哈希值,后者直接记录URL,并用back/forward/go方法后退、前进和跳转页面

v指令

・v-bind是单向数据绑定,v-model是双向数据绑定
——v-model的双向绑定是v-bind(父传子)和v-on(子传父)结合的语法糖
・v-for:遍历渲染组件,Vue2中v-for优先于v-if,而Vue3中v-if优先于v-for
——v-for的标签格式为v-for=“item in/of arr”,两参数是(val, index),三参数是(val, key, index)
・v-if:根据条件决定是否渲染组件,可以和v-else-if、v-else结合用作分支语句
——尽量避免将v-for和v-if写在一起,要写一起的话在外面套个<template v-if>,它会计算但不渲染
・v-on/@:触发内置事件或自定义事件,并执行相应的回调函数
・v-show仅隐藏组件,v-if隐藏节点

组件的通信方式

・父传子:父用v-bind绑定变量,子即可从props属性接收
・子传父:子用$emit发送消息,父在"@事件名"中会触发相应事件
・父也可以用$refs查找具有对应ref标签的子元素的属性
・使用了ref标签后,可以根据$refs查找具有对应ref值的组件
・父传孙:父在provide函数里提供属性,子孙后代都会被注入对应的inject属性
・非父子组件传值:用事件总线eventBus的emit和on传值
・Vue中的事件名以v-on/@而非on开头
・$nextTick在下次DOM更新循环结束之后执行延迟回调,以等待所需参数计算完成

元素修饰符

・stop防冒泡,prevent防默认事件
・capture:与事件冒泡的方向相反,事件捕获由外到内
・self:只触发自己范围内的事件,而不波及子元素;
・once:只触发一次

响应

・diff算法:用于比较节点数中同一层的节点的变化情况(增加/编辑/删除)
・对于data的数组或对象,直接通过索引修改值可能无法被Vue检测,但若是元素数量有变则会捕捉到

算法

排序

・冒泡排序:最好O(n),其余O(n²),常数空间:一直循环,遇前>后就交换,无就算排好,稳定
・插入排序:皆O(n²),常数空间:循环选择后面部分第一个数插到前面排好序的部分,稳定
・选择排序:最好O(n),其余O(n²),常数空间:循环选择后面最小的数的插到前面有序部分的尾部
・归并排序:皆O(nlogn),空间O(n):先将序列递归分成两个子序列,分别对子序列排序,然后对上一级序列排序,稳定
・堆排序:皆O(nlogn),常数空间:把数组变成完全二叉树,再把它变成小根堆
・快速排序:最好O(nlogn),平均 O ( n 1.5 ) O(n^{1.5}) O(n1.5),最坏O(n²),空间O(logn):将第一个数作基准,大的搁前面,小的搁后面,如此递归
・希尔排序:最好O(nlogn),其余O(nlog²n),常数空间:先令gap=length/2,依次将第i、i+gap、i+2gap……等元素划成一组作插入排序,然后令gap=gap/2,继续分组插入排序,如此往复,最后gap=1即对整个数组插入排序

二分

・二分查找是将值二分,折半查找是将序号二分

LRU

・LRU(Least Recently Used)算法在缓存空间不足则先淘汰最近最少使用的缓存数据
——其维护一个缓存列表,访问数据时将该数据移到列表前面,表示其最近被访问过;淘汰数据时将列表尾部的数据淘汰,因为它们是最近最少被访问的
——实现方式是使用哈希链表,使用链表是因为有序且容易插入和删除,使用哈希表是便于索引链表节点
——LRU算法的优点是能够保证缓存中的数据都是热点数据,也就是最近被访问的数据,因此可以有效地提高缓存命中率
——其缺点是实现较为复杂,需要维护一个有序的缓存列表,并且每次访问数据都需要更新列表,对性能有一定的影响

智力题

・大多考的是数学(相遇、概率)、推理(过河、真谎)、数论(倒水、阶乘)、算法(天平、烧香)和二进制(分金链、找毒药)
・最难的是循环报数问题

### 前端社会招聘试经验 #### 试前准备 对于前端开发的社会招聘,拥有扎实的技术背景和实际项目经验至关重要。在准备过程中,候选人应确保简历中的每一项技能声明都经过深思熟虑,并准备好应对与之相关的深入探讨[^1]。 #### 项目展示的重要性 由于应聘者通常已经具备一定的工作经验,在试中强调个人参与的具体项目及其成果显得尤为重要。这不仅能够证明候选人的技术水平,还能体现解决问题的能力以及团队协作精神。因此,建议提前整理好可以讨论的成功案例或重要贡献,特别是那些运用到前沿技术和创新解决方案的部分[^2]。 #### 应对技巧 当被询问关于职业发展的动机时,应当保持积极正的态度,专注于描述如何能为企业带来价值而非仅仅关注于薪资待遇等方的变化。分享一次最具成就感的工作经历也是一个很好的切入点,借此机会展现软实力和个人成长轨迹[^3]。 #### 实际案例说明 举例来说,“我曾主导过一个名为XX的重点项目,其核心目标在于提升用户体验并优化性能表现;在此期间本人主要承担了XX模块的设计与实现工作,利用React框架有效改善了页加载速度。” 这样的叙述方式既具体又具有说服力,有助于给试官留下深刻印象[^4]。 ```javascript // 示例代码片段用于解释技术细节 function optimizePageLoad() { // 使用 React 的懒加载特性来延迟非首屏组件的渲染 const LazyComponent = React.lazy(() => import('./LazyComponent')); return ( <Suspense fallback={<div>Loading...</div>}> <LazyComponent /> </Suspense> ); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值