. 前端面试题
let 与 var 的区别?
let 1.有局部作用域
var 1.声明提前 。2.没有局部作用域。3. 声明覆盖
赋值
原数组会不会改变?(这是引用数据类型的考题)
答案是原数组会改变,因为数组和对象的赋值后,对新的数组,对象进行操作会影响原数组或对象。但是如果是 (...arr)的话就不会再改变原数组(只对一维数组有效,多维数据无效【【1,2,3】,{1,2,3} 】)。使用JSON.parse(JSON.stringify())这样嵌套可以解决原数组会改变的问题。但是这里还有问题例如 funcion是不能复制的。完美解决的方法如下
关于promise
promise目前是JS最好的异步处理方案。promise本身是同步的,但是用于接收的回调函数“.then是异步的”,也是为了解决异步(我会返回给你一个东西,但是我需要时间操作)。
下面是题目注意看!
手写一个promise(这点非常重要!!!这点非常重要!!!这点非常重要!!!)
输入URL 的那一瞬间浏览器做了什么?
url => 这个叫统一资源定位符(就是网址)url是IP地址的映射。
https://www.baidu.com (www代表服务器,https是传输协议http在TCP之间加了一层TSL或者SSL的安全层,baidui.com代表域名)
www.baidu.com =》 DNS域名系统 =》 解析拿到真是IP =》建立连接(TCP三次握手) =》拿数据渲染页面=》四次握手(如果是第二次访问的话上次访问的时候会将解析的域名存在本地,读取浏览器缓存查看域名被解析过的地址是否过期)
怎么做性能优化?(1.页面加载性能。2.动画于操作性能。3.内存占用。4.电量消耗)
一.加载:1.减少http请求(精灵图文件合并,小图片转bese64)。 2.减小文件大小(资源,图片,代码的压缩)。 3.CDN(第三方库,大文件,大图)。 4.SSR服务器渲染。预渲染。 5.图片懒加载。 6.分包
二 减少DOM操作,避免回流,文档碎片
this
此时的this指向是 B ,在这里this指向只会是上级调用,类似于谁调用就指向谁
能改变this的方法 1.bind()不调用 只改变this指向。2.call apply()改变之后会执行一次 (apply =>【】)(call=>{}) 这两个传的参数不同
闭包( 闭包是方法返回一个方法 )
闭包是一个函数加上到创建函数的作用域的连接,闭包关闭了函数的自由变量
1.避免变量被污染。 2.私有化。 3.保存变量,常驻内存。 4.闭包应用的场景 :防抖,节流,库的封装(保证数据的私有化)。
下面makeCounter方法向外暴露了三个方法(increment,decrement,value),还有一个私有变量privatrCounter和一个私有方法changeBy是无法访问的。value方法有返回privateCounter才能正常获取。
new关键字
new的时候都做了什么?
1.创建了一个对象 。 2.设置原型链。 3. 改变this指向。 4.判断返回值类型(构造函数会默认返回新创建的对象)
事件委托
事件委托是利用冒泡的机制实现的,将事件绑定给元素的父级通过元素冒泡触发事件。不管是新创建的元素还是本来就存在的标签都可以适用。
event参数是自带的参数,通过target属性里面的nodeName判断触发事件的标签名来进行筛选自己想委托的对象(注意nodeName是大写)
延迟加载JS的方式有哪些?有什么区别?
async: async是和HTML同步加载,不是顺序加载JS脚本(谁先加载完成谁先执行)
defer:defer等HTML全部解析完成才会执行JS代码 ,顺序执行脚本(如果JS有依赖关系可以用这个保持顺序加载执行)
JS的数据类型那有哪些?
分为两类:基本数据类型:string, boolean, undefined, null, number,symbol,bigint
引用数据类型 object
隐式数据类型转换
答案依次是 2 name1 NaN Object 在相加的过程中会进行隐式数据类型转换
null和undefinde的区别
设计两个为“无”的缘由 1.作者在设计JS的时候先设计null(为什么设计null:最初设计js的时候借鉴了java的语言) 2.null会被隐式转换成0,很不容易发现错误。 3.先有null后有undefined,出来undefined是为了填补之前的坑。
JavaScript的最初版本是这样区分的:null是一个表示“无”的对象(空对象指针),转换数值为0;undefined是一个表示“无”的原始值,转换数值为NaN。
==和===有什么不同?
==表示值相等就为真。===表示值和数据类型都相等。注:两等会通过valueOf函数进行隐式数据类型转换。(通常有JS在后台自动调用,并不显示)
JS的微任务和宏任务
1.JS是单线程语言。 2.JS代码执行流程:同步任务执行完执行事件循环任务。(事件循环又分微任务和宏任务),同步任务都执行完了才会执行时间循环内容,能进入事件循环的任务有:请求,定时器,事件 ~~ 3.事件循环中又包含了【宏任务与微任务】。 执行顺序为:同步任务=》事件循环(微任务=》宏任务)
作用域
一段程序代码中所用到的名字不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域
1. JS是没有块级作用域的(函数,let有作用域) 2.作用域链:内部可以访问外部的变量,但是外部不能访问内部的变量。如果内部有,优先查找内部,如果没有才继续向外查找。 3. 如果变量声明用var还是没有写(window.) 4.JS有变量提升的机制【变量悬挂生命】(也行是生命提前吧) 5.声明的优先级是:参数 > 变量声明 > 函数声明
JS对象注意点
什么是面向对象:对某一类事物进行抽象,抽象出这一类事物共同的特征以及行为(也就是属性和方法),那些拥有这一共同属性和方法的事物就是对象
1.对象是通过new操作符构建出来的,所以对象之间不相等。 2.对象注意:引用类型。(共同一个地址) 3.当对象作为key值的时候都是字符串类型(obj[对象],实际得到的键值都是object) 4.对象如何找属性 | 方法 先在对象本身上找 》构造函数上找 》对象原型上找 》构造函数原型上找 》对象上一层原型查找
console.log( [1,2,3]===[1,2,3])(答案是false)通过new出的新对象都是一个全新的对象,但是引用数据是除外的
JS判断变量是否为数组,你能用几种方法?
1. Array . isArray(arr) 使用数组自带的方法 2.arr.constructor constructor会指向自己缔造的基类 3.arr instanceof Array 检测构造函数的属性是否出现在原型链(不严谨可以不写) 4.Object.prototype.toString.call(arr).indexOf('Array') != -1 原型prototype 5.Array.prototype.isPrototypeOf(arr)
slice是干嘛的?splice是否会改变原数组?
1.slice是用来截取的 slice(-3)但从数组的倒数第三个开始截取; slice(1,3)从第一个截取到第三个;slice会返回全新数组,不会改变原数组。
2.splice可以插入,删除,替换,会改变原数组 arr.splice(1,1)【从第一个删除一个,会返回一个数组数组里面是被删掉的元素】;arr.splice(1,1,'nihao')【从第一个删除一个,把“nihao”插入到被删掉的位置】;
JS数组去重
1.Array.from(new Set(arr)) ES6新增方法把像数组的内容变成真正的内容 2.[...new Set(arr)] ES6的拓展运算符展开。应该算是一中方法吧 3.for也可以换成filter
4.
取多维数字中的最大值
给字符串新增方法实现功能
找出字符串出现次数最多的字符以及出现几次
new具体做了什么?
1.创建了一个空对象; 2.将空对象的原型,指向构造函数的原型; 3.将空对象作为构造函数的上下文(其实就是改变this指向); 4.对构造函数有返回值的处理判断 【return result instanceof Object ? resule : obj 】
ES6的新特性
1.const和let
let有块级作用域,没有类似于var的声明提升,也不允许重复声明
const声明是一个不可被改变的常量,声明时必须赋值
【 面试中常会问到var let const 三都的区别,回答的时候注重各自的特点,其实const let就是弥补var 的各种缺点,两都的特点就是var 的缺点。
工作中声明变量多用const 和 let
其中当声明的变量为引用类型如Array,如果没有直接更改引用的地址,可以使用const 】
2.解构赋值
①解构赋值的定义:按照一定模式从数组或对象中提取值,然后对变量进行赋值(先提取,再赋值)
数组:
let[a,b]=[1,2]
// 以下的结果为右边数剩下的值所组成的数组
let[c,d,...e]=[1,2,3,4]
// 有默认值的写法
let[f=100]=[]// f = 100
// 其中String也被视为类数组
let[a,b]='abcd'// a = a; b = b
对象:变理名要与对象的属性名一样才可以;
let { foo } = { foo: 1, bar: 2 } // foo = 1
// 重新命名(后面那个才是新变量)
let { foo: newFoo } = { foo: 1, bar: 2 } // newFoo = 1
③交换两个变量的值 [x,y]=[y,x]
④ 函数的封装
functionfn( {x,y}={} ){
console.log(x,y)
}
其中,函数参数为一个对象,不会像(x, y)的形式这样固定参数的顺序,而{} = {}后面又赋一个空的对象就是为了在调用fn时不传参数而不会抛出错误导至程序中止
⑤函数返回值的结构
有序次的 function fn(){
return [a,b,c]
}
let [a,b,c]=fn(); 无次序的返回值使用对象承载的即{b,c,a}
3.模板字符串
consth='hello'
` $ { h } word `
可以换行,但是所有的空格和换行会被保留。
${}中可以使用任意的javaScript表达试、运算、引用对象属性、函数调用等。结果是其返回值。
4.函数的扩展
①函数的默认值 functionm(x=1){ }
②rest参数(用于获取函数的多余参数)
function a(...values){// value 是一个数组,第个元素是传入的各个参数 }
5. 箭头函数
特点:
函数体内的this = 定义时所在的对像
不可以当作构造函数(不能用new)
不可以用arguments对像,可以用rest
不可以用yield命令(不能用作Generator函数)
6. 数组的拓展
call apply bind的区别:
用于改变this的指向, 第一个参数为this指向的对像,后面的参数是作为函数的参数。
区加在于:call apply 会即调用,而bind是生成一个等调用的函数。call bind参数是一个个用逗号罗列,而apply 是传入一个数组。
fn.apply(null,[1,2,3])
fn.call(null,1,2,3)
fn.bind(null,1,2,3)()
Math.max(...[3,4,5,62,8]) 指最大值
[1, 2, ...[3] ] //数组合并
7.新增的方法
Array . from(arr)//将类数组转化为数组
find()findIndex()找出第一个符合条件的成页/下标(位置)
entries()keys()values() 用于遍历数组。(配合for...of)
entries()keys()values() 用于遍历数组。(配合for...of)
8.对象的扩展
let a = 100 {a} // 等同于 {a:100}
{//这是简写 {//这是对象的写法
a:'你好', a:'你好',
data () {} data:function(){}
} }
新增的方法
Object.is(value1,value2);//判断两个值是否为同一个值
Object.assign( obj1,obj2,obj3) 会合并成一个对象,其中相同的属性名会被后面相同的覆盖
for(letkeyofObject.keys(obj)){} 返回对象中键值对的键放在数组中,顺序是在对象中的顺序
for(letvalueofObject.values(obj)){} 返回数组中包含了键值对的值,顺序是对象中的顺序
for(let[key,value]ofObject.entries(obj)){}将对象中的键值对分开放在一个数组中,再把所有数组放在一个数组中进行返回
9. Symbol:symbol作为对象的属性名时不会被for...in,for...of,Object.keys()识别;可以改用Reflect.ownkeys方法
10. Set、Map
①Set类似数组,但是其值具有唯一性。可以用来去重
Array.from(...new Set([1,8,6,3,2,1,,7,5,6,8,5,] ))配合from可获得去重后的数组
②Map 为了解决javascript的对象只能用了符串作为键的问题。
用法: (使用实例的set,get,delete方法增,查,删)
constm=newMap()constobj={a:'aa'}
m.set(obj,'obj as key')
m.get(obj)// 'obj as key'
m.delete(obj)
11.Promise是异步编程的一种解决方案。
特点:①状态不受外界影响(有三种状态:padding, fulfilled,redected)
②状态一旦发生改变就不会再更改
constp=newPromise((resolve,reject)=>{
setTimeout(()=>{resolve()},1000)
}).then(res=>{})
.catch(err=>{})
.then(res=>{},err=>{})这个方法有两个参数,第一个成功回调,第二个失败回调;但是最好用catch方法, 因为catch方法会捕获then里的错误,then里有错误程序不会中止。
Promise.all()//将一组promise包装成一个promise varpa=Promise.all([p1,p2,p3])
当所有都fulfilledj时,promise.all才fulfilled
当只有一个rejected时,promise.all就会rejected
Iterator和for...of
1.为各种数据提供统一的,简便的访问接口
2.使数据结构的成员能按某种次序排列
3.主要供for...of用
Generator与async await
generator是ES6提供的一种异步编程解决方案。使异步写法更像同步。
Async await是ES2017的标准,是generator的一个语法糖。
asyncfunctiona(){
await...
console.log(111)
await...
}
console.log('开始')
a()
console.log('a后面')// 开始 -> a后面 -> 111
console.log('开始')a()console.log('a后面')// 开始 -> a后面 -> 111
JS继承有哪些方式
ES6 构造函数继承 原型链继承 还有组合式继承(原型链和构造函数的融合)
CALL,Apply,Bind有什么区别?
共同点是,改变函数体内的this指向
不同点是 call apply谁立即执行一次函数,bind不会立即执行会返回一个函数
Symbol