biubiubiu...

前端基础整理

1-1. var let const 区别

  • var 是es5语法,有变量提升
  • let const是es6语法, 有块级作用域
  • var let 是变量,可修改;cosnt是常量,不可修改

2-1. typeof返回哪些类型

  • 值类型:undefined string number boolean symbol
  • 引用类型: object,注意:typeof null === 'object'
  • function
  1. 列举强制类型转换和隐式类型转换
  • 强制:parseInt parseFloat toString等
  • 隐式:if、逻辑运算、==、 +拼接字符串

2-2. 手写深度比较,模拟lodash isEqual

const obj1 = {
  a:100,
  b: {x:100,y:200}
}
const obj2 = {
  a:100,
  b: {x:100,y:200}
}

// 判断是否是对象、数组
function isObject(obj){
  return typeof obj === "object" && obj !== null  
}

function isEqual(obj1,obj2){
  if(!isObject(obj1)||!isObject(obj2)){
    // 值类型 (参加equal的一般不是函数)
    return obj1 === obj2
  }
  if(obj1 === obj2){ // 同一对象
    return true; 
  }
  // 两个都是对象或数组,且不相等
  // 1. 先取出obj1和obj2的keys,比较个数
  const obj1Keys = Object.keys(obj1)
  const obj2Keys = Object.keys(obj2)
  if(obj1Keys.length !== obj2Keys.length){
    return false
  }
  // 2. 以obj1为基准,和obj2依次地柜比较
  for(let key in obj1){
    // 比较当前key的value  -- 递归
    const res = isEqual(obj1[key],obj2[key])
    if(!res){
      return false
    }
  }
  // 3. 全相等
  return true
}
console.log(isEqual(obj1,obj2)) // true
  1. split()和join() 区别
  • '1-2-3'.split('-') // [1,2,3]
  • [1,2,3].join('-') // 1-2-3

2-3. 数组的pop push unshift shift 区别

pop push unshift shift
功能 删除最后一个 在最后加一个 在开头加一个 删除开头一个
返回值 最后一个数 数组长度 数组长度 开头的一个数
  • 是否会对原数组造成影响

// 纯函数: 1. 不改变原数组(没有副作用); 2. 返回一个数组
const arr = [10,20,30,40]

// concat
const arr1=arr.concat([50,60,70])
// map
const arr2 = arr.map(num=>num*10)
//filter
const arr3 = arr.filter(num=>num>25)
// slice 类似一个深拷贝
const arr4 = arr.slice()

// 非纯函数
// push pop shift unshift
// forEach
// some every
// reduce

3-1. 数组slice(切片)和splice(剪接)区别:

  • 参数和返回值
  • 是否是纯函数,slice是纯函数
slice splice
}返回值
是否是纯函数

3-2. [10,20,30].map(parseInt)

返回[10,NaN,NaN]
等同写法:

[10,20,30].map((num,index)=>parseInt(num,index))
// parseInt 按照index进制格式化num

3-3. ajax请求get和post区别

  • get用于查询,post用于提交
  • get参数拼接在url上,post参数在请求体内,且更大
  • 安全性:post更易于防止CSRF

4-1. 函数call和apply的区别

  • 第二个参数不同
  • fn.call(this,p1,p2,p3...)
  • fn.apply(this,[p1,p2,p3...])

4-2. 事件代理(委托)是什么

const p1 = document.getElementById('p1')
const body = document.body
bindEvent(p1,'click',e=>{
  e.stopPropagation() // 注释掉这一行,可以体会到事件冒泡
  alert('激活')
})

bindEvent(body,'click',e=>{
  alert('取消')
})

4-3. 闭包是什么?有何特性?有何影响?

  • 影响:常量常驻内存,得不到释放。闭包不可乱用

5-1 如何阻止事件冒泡和默认行为?

  • event.stopPropagation()
  • event.preventDefault()

5-2 查找、添加、删除、移动dom节点的方法?

  • 查找:document。getElementById/TagName/ClassName/ querySelectorAll(xx)
  • 新建: document.createElement('xx ')
  • 插入: div.appendChild(xx)
  • 移动:先获取,再插入
  • 删除子元素: parentDiv.removeChild(xx)

5-3 如何减少dom操作

  • 缓存DOM查询结果
  • 多次Dom操作,合并到一次插入
const list = document.getElementById('list')

// 创建一个文档片段,此时还没有插入到DOM结构中
const frag = document.createDocumentFragment()

for(let i=0; i<20; i++){
  const li = document.createElement('li')
  li.innerHTML = "item ${i}"
  // 先插入文档片段中
  frag.appendChild(li)
}
// 都完成之后,统一插入到 DOM结构中
list.appendChild(frag)

6-1: 解释jsonp原理,为何不是真正的ajax

  • 浏览器的同源策略(服务端没有同源策略)和跨域
  • img、script、标签可以绕过跨域
  • 不走xmlhttp 接口,需要服务端支持
<script>
  window.abc = function(data){
    console.log(data)
  }
</script>

// 把function abc作为回调函数传给后端
<script src="http://localhost:8002/jsonp.js?username=xxx&callback=abc"></script>

// 后端 jsonp.js 处理:
abc{
  {name:'jsonp666'}
}

6-2. document load 和 ready 的区别

window.addEventListener('load',function(){
  // 页面的全部资源加载完才会执行,包括图片、视频等
})

document.addEventListener('DOMContentLoaded',function(){
  // DOM渲染完即可执行,此时图片、视频可能还没加载完
})

6-3. == 和 === 的区别

  • ==会尝试进行类型转换
  • === 严格相等
  • 只有判断null或undefined 时才用

7-1 函数声明和函数表达式的区别

  • 函数声明 function fn()
  • 函数表达式 const fn = function()
  • 函数声明会在代码执行前预加载(类似变量提升),函数表达式不会

7-2 new Object() 和 Object.create() 区别

  • {}等同于new Object(), 原型Object.prototype
  • Object.create(null),没有原型
  • Object.create({...}), 将原型对象指向
  • obj1 === obj2时,两个对象的地址是一样的

7-3 this传统场景题

  • this的值在执行时决定

8.1 作用域和自由变量1

let a = 100;
function test(){
  alert(a)
  a = 10 
  alert(a)
}

8.2 判断字符串以字母开头,后面字母数字下划线,长度6-30

  • const reg = /[1]\w{5,29}$/
  • ^ xx开头
  • \w: 字母、数字、下划线
  • $: 结尾
  • \d:数字
    • : 一次到多次
  • 用户名:/[2]/
  • 简单ip地址: /\d+.\d+.\d+/
  • 日期(2019.12.1):/^\d{4}-\d{1,2}- \d{1,2}$/

9-1 手写trim并保证浏览器兼容性

String.prototype.trim = function(){
  // 直接放到原型上有点暴力,其实应该先判断一下,原型上是否有,没有再整
  // 通过正则解决兼容性问题
  return this.replace(/^\s+/,'').replace(/\s+$/,'')
}

9-2 获取最大值

function max(){
  const nums = Array.prototype.slice.call(arguments); // 变为数组
  let max = 0;
  nums.forEach(n=>{
    if(n>max){
      max = n
    }
  })
  return max;
}

Math.max([1,2,3,4,5])

9-3 如何用js实现继承

  • class
  • prototype

10-1 如何捕获js中的异常?

// 高风险的地方
try{
  // todo
}catch(ex){
  console.error(ex) // 手动捕获 catch
}finally{
  // todo
}

// 自动捕获
window.onerror = function(message,source,lineNum,colNum,error){
  //1. 对跨域的js,如 cdn,不会有详细的报错信息
  // 2. 对于压缩的js,还要配合sourceMap反查到未压缩代码的行、列

10-2 什么是JSON

  • JSON是一种数据格式,本质是一段字符串
  • json格式和js对象结构一致(键值对),对js语言更友好,但是json中只能用双引号
  • window.JSON是一个全局对象:JSON.stringify JSON.parse

10-3 获取当前页面的URL参数

  1. 传统方式:location.search
function query(name){
  const search = location.search.substr(1) // substr(1)是为了取消?,类似array.slice()
  // search:‘a=10&b=20&c=30’
  const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`,'i')
  const res = search.match(reg)
  if(res === null){
    return null
  }
  retrun res[2]
}
  1. 新api:URLSearchParams,兼容性需要做处理
function query(name){
  cosnt search = location.search;
  const p = new URLSearchParams(search);
  return p.get(name)
}

11-1 将url参数解析为js对象

// 方法1
function queryToObj(){
  const res = {}
  const search = location.search.substr(1)
  search.split('&').forEach(paramStr=>{
    const arr = paramStr.split('=')
    cosnt key = arr[0]
    const val = arr[1]
    res[key] = val
  })
  return res;
}

// 方法2
function queryToObj(){
  const res = {  }
  const pList = new URLSearchParams(location.search)
  plist.forEach((val,key)=>{
    res[key] = val
  })
  return res;
}

11-2 手写数组flatten,考虑多层级

// arr = [1,[2,3,[4,5,[6.7],8],9]
function flat(arr){
// 验证arr中,是否有深层数组
const isDeep = arr.some(item=>item instanceof Array)
is(!isDeep){
return arr // 平的,直接返回
}
const res = Array.prototype.concat.apply([],arr)
return flat(res) // 递归
}
const res = flat(arr)

// 不考虑层级,可以用concat(只能拍平一层)
arr2 = [1,2,[3,4],5]
Array.prototype.concat.apply([],arr2)
Array.prototype.concat.call([],...arr2)
[].concat(...arr2)

11-3 数组去重

  1. 传统方法
function unique(arr){
  const res = []
  arr.forEach(item=>{
    if(res.indexOf(item)<0){
      res.push(item)
    }
  })
  return res
}
  1. 使用 es6 Set(无序,不允许有重复),不需要遍历,效率高于传统方式
function unique(arr){
  const res = new Set(arr)
  return [...res]
}

12-1 手写深拷贝

注意:Object.assign 不是深拷贝,且有副作用

12-2 RAF requestAnimationFrame

  • 想要动画流畅,更新频率要60fps/s,即16.66ms更新一次视图
  • setTimeout 要手动控制频率,而RAF浏览器会自动控制(根据屏幕刷新率)
  • 后天标签或隐藏iframe中,RAF会暂停,而setTimeout依然会执行

let curWidth = 100;
const maxWidth = 640;
function animate(){
  curWidth = curWidth + 3;
  $div1.css('width',curWidth)
  if(curWidth < maxWidth){
    window.requestAnimationFrame(animate)
  }
}
animate()

12-3 性能优化

  • 原则:多使用内存、缓存,减少计算、减少网络请求
  • 方向:加载页面,页面渲染,页面操作流畅度

  1. a-zA-Z ↩︎

  2. a-zA-Z\w ↩︎

posted @ 2021-03-06 13:57  了恩  阅读(78)  评论(0编辑  收藏  举报