• 大钱端之面试(中)


    大钱端之面试(中)

    JS基础

    JS基础-变量类型和计算

    typeof 能判断哪儿些类型

    识别出所有值类型 : string char symbol undefind blooean
    识别函数 : funtion
    识别引用类型 Object(到此为止,不可再细分)
    

    何时使用 === 何时使用 ==

    ==运算符 会尽量转换成相同类型使之相等

    除了等于null之外,一律用三等

    值类型和引用类型的区别

    值类型 : string char symbol undefind blooean
    let a = 100
    let b = a
    a = 200
    console.log(b)
    
    引用类型 :  [] {} null  特殊引用类型 |函数类型 function(){} 
    let a = { age : 20 }
    let b = a
    b.age = 30
    console.log(a.age)
    
    分析
    栈  a | 100
    栈  a | 100  b | 100
    栈  a | 200  b | 100
    
    存储的是内存地址
    堆  内存地址1 | { age : 20 }
    堆  内存地址1 | { age : 20 }
    堆  内存地址1 | { age : 21 }
    

    ​ 性能及内存原因,js机制如此

    手写深拷贝

    注意判断值类型与引用类型 :typeof

    注意判断数组还是对象 :instanceof

    function deepClone(obj = {}) {
        // 初始化返回结果
        let result
        if (obj instanceof Array) {
            result = []
        } else {
            result = {}
        }
        for (let key in obj) {
            // 保证 key 不是原型的属性
            if (obj.hasOwnProperty(key)) {
                // 递归调用!!!
                result[key] = deepClone(obj[key])
            }
        }
        return result
    }
    

    变量类型相关的面试题

    • 字符串拼接

    • == 判断

    • truely falsely 变量

      const n = 100  两部运算后等于true 则为truely变量,反之亦然
      !n
      !!n   <--  trurly变量
      
      if(truely)
      

    JS基础-原型与原型链 <基于原型来集成>

    知识点:

    object可以认为是所有class的父类

    class实际上是一个函数

    >_ typeof class student{}
    >_ function
    
    student.__proto__
    student.prototype
    student.prototype.__proto__ === people.prototype
    
    suduent 的属性属于自身
    		方法指向到父类的__proto__
    

    每个class都有显示原型 prototype

    实例中的 _ proto _ 对应class的prototype

    hasownproperty 验证是否为自身属性

    hasownproperty 是object._ proto _的隐式原型中提供的方法

    object._ proto _ 永远指向null

    至此原型链结束

    基于原型的执行规则
    • 先在自身的属性和方法寻找
    • 找不到自动去上层的 隐式原型 _ proto _中寻找

    instanceof 判断引用类型

    instanceof 的原理

    通过隐式原型在原型链上寻找,找到这个属性方法,返回true 找不到返回false

    提示

    class是es6语法规范,由ECMA委员会发布

    ECMA委员会发布只规定书写规范,不关心如何实现

    以上原型都是通过v8引擎的实现发布,也是主流引擎

    原型面试题

    如何判断一个变量是不是数组

    a instanceof array

    class的原型本质,怎么理解

    原型与原型链的图示

    属性和方法的执行规则

    手写jquery ,考虑插件与扩展性

    class jQuery {
    	//构造
        constructor(selector) {
            const result = document.querySelectorAll(selector)
            const length = result.length
            for (let i = 0; i < length; i++) {
                this[i] = result[i]
            }
            this.length = length
            this.selector = selector
        }
        get(index) {
            return this[index]
        }
        each(fn) {
            for (let i = 0; i < this.length; i++) {
                const elem = this[i]
                fn(elem)
            }
        }
        on(type, fn) {
            return this.each(elem => {
                elem.addEventListener(type, fn, false)
            })
        }
        // 扩展很多 DOM API
    }
    
    // 插件
    jQuery.prototype.dialog = function (info) {
        alert(info)
    }
    
    // “造轮子”
    class myJQuery extends jQuery {
        constructor(selector) {
            super(selector)
        }
        // 扩展自己的方法
        addClass(className) {
    
        }
        style(data) {
            
        }
    }
    
    // const $p = new jQuery('p')
    // $p.get(1)
    // $p.each((elem) => console.log(elem.nodeName))
    // $p.on('click', () => alert('clicked'))
    
    

    JS基础-作用域及闭包

    知识点

    作用域和自由变量

    作用域:

    一个变量的合法使用范围

    • 全局作用域
    • 函数作用域
    • 块级作用域 {}
    自由变量 :

    一个变量在当前函数体被使用,但没有找到,则一层一层递增查找

    所有自由变量的查到,实在函数定义的时候想上寻找,而不是在函数执行的地方向上寻找

    • 如果没有找到,则报 xx is not defind

    闭包 closure

    作用域应用的特殊情况,有两种情况

    • 函数作为返回值
      function create() {
          const a = 100
          return function () {
              console.log(a)
          }
      }
      
      const fn = create()
      const a = 200
      fn() // 100
      
    • 函数作为参数
      function print(fn) {
          const a = 200
          fn()
      }
      const a = 100
      function fn() {
          console.log(a)
      }
      print(fn) // 100
      

      !!! 所有自由变量的查到,实在函数定义的时候想上寻找,而不是在函数执行的地方向上寻找

    this

    this 有几种赋值情况
    • 作为普通函数 < 指向 window >
    • 使用 call bind apply < 指向执行体,传入什么绑定什么 >
    • 作为对象方法被调用 < 返回当前对象 >
    • 在class方法中被调用 < 返回class实例本身 >
    • 箭头函数 < 找上级作用域的this来确定 >

    this取什么值,是在函数执行的时候定义的,而不是创建的时候 , 适用于以上场景

    面试题:

    1. this的不同应用场景,如何取值

    ​ 上面已回答

    2. 手写bind函数 [改变指向的方法之一]

    **bind()** 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

    Function.prototype.bind1 = function (){
        把传入的参数变为数组
        .call 是把arguments赋值成为当前参数的this   复习 【指向执行体,传入什么绑定什么】
        const args = Array.prototype.slice.call(arguments)
    
        剔除args[0]并赋值给变量t  <也就是传入的this>
        const t = args.shift()
    
        // self 就是调用bind方法的函数本身
        const self = this
    
        // 返回一个函数
        return function(){
            return self.apply(t,args)
        }
    }
    

    3. 实际开发中闭包的应用场景,举例说明

    • 隐藏数据

    • 做一个简单的cache工具

      function createCache(){
      	const data = {}
      	return {
      		set:function(key ,value){
      			data[key,value]	
      		},
      		get:function(key){
      			return data[key]
      		}
      	}
      }
      

    4. 创建10个A标签,点击弹出对应的序号

    let a
    for(let i = 0;i < 10 ; i++){
    	a = document.createElemeat('a')
    	a.innerHtml = i+'<br>'
    	a.addEventListener('click',function(e){
    		e.prevenDeafualt()
    		e.alert(i)
    	})
    	document.body.appendchild(a)
    }
    

    JS基础-异步

    JS三座大山 原型和原型链 作用域和闭包 以及异步和单线程

    Promise 解决了 callback hell的问题

    JS是一门单线程语言,只能同时干一件事

    浏览器和nodejs已经支持js同时启动进程,例如web worker

    js和DOM渲染同时使用同一个线程,因为JS可以修改DOM结构 <DOM渲染过程中JS必须停止,JS执行过程中也必须停止 >

    遇到等待,(定时任务,网络请求),页面不能卡住

    需要异步

    异步是基于callback函数形式来调用的

    异步 :

    • 基于JS是单线程语言
    • 异步不会阻塞代码执行
    • 同步会阻塞代码执行

    异步的应用场景:

    • 网络请求 : 如 ajax图片加载
    • 定时任务 : setTimeout setInterval
    • 解决回调地狱 promise把回调变成了管道类的形式,而不是嵌套,越陷越深.

    面试题

    同步和异步的区别是什么

    阻塞线程的区别

    • 基于JS是单线程语言
    • 异步不会阻塞代码执行
    • 同步会阻塞代码执行

    手写promise加载一张图片

    const url1 = 'xxx.jpg'
    
    const getImage (src){
    	return new Promise((resolve,reject)=>{
    		const img = document.careteElment('img')
    		img.onload = () => {
    			resolve(img)
    		}
    		img.onerror = () =>{
    			const err = new Error(`err info :${src}`)
    			rject(err)
    		}
    		img.src = src
    	})
    }
    

    前端异步的使用场景有哪儿些

    • 网络请求 : 如 ajax图片加载
    • 定时任务 : setTimeout setInterval

    JS-异步进阶

    JS异步的原理及进阶

    • event-loop

      请描述 event-loop 的机制,可画图 别名:《事件循环/事件轮询》

    • Promise进阶

      Promise有哪儿三种状态,如何变化

      Promise then与catch的连接

      Promise 和 setTimeout 的顺序

    • aysnc await

      async await 语法

    • 微任务 / 宏任务

      什么是微任务,宏任务,两者有啥子区别

    什么是event-loop (事件循环/事件轮询)

    • JS 是单线程
    • 异步通过回调来实现

    event loop就是异步回调的实现原理

    JS是如何执行

    • 从前到后,一行一行执行 , 如果中间有一行报错,则停止执行
    • 先把同步代码执行完,再执行异步
    console.log('hi')
    
    setTimeout(function cb1(){
    	console.log('cb1')
    },5000)
    
    console.log('bye')
    

    以上JS代码执行过程

    call stack (调用栈)--> web apis (处理api)--> callback queue (回调函数队列)--> Event loop (事件循环)

    hi 的执行顺序:

    1. call stack 放入 console.log('hi') 
    2. browser console output: hi 
    3. call stack (empty)
    

    setTimeout 的执行

    1. call stack 放入 setTimeout cb1
    2. web apis  放入定时器 timer cb1   > 5秒钟的定时器
    3. 5秒钟的定时器结束后 > cb1 放入 callback queue
    

    bye 的执行顺序:

    1. call stack 放入 console.log('bye') 
    2. browser console output: bye 
    3. call stack (empty)
    

    所有同步代码执行完成后(调用栈为空),启动event loop机制

    1.启动后在 callback queue轮询查找
    2.在callback queue里找到cb1 推到 ,call stack里执行函数体cb1
    3.执行cb1,打印 cb1  ,完成后从调用栈 清空
    4.继续轮询查找 (~永动机一样~)
    5.JS语句执行完毕
    

    DOM事件和event-loop的关系

    DOM事件也是基于回调来实现的
    只要是基于回调,就是基于eventloop来实现的

    btn的click触发
    当执行到绑定click JS语句是,把click方法推到webapi存储,当用户点击时触发,webapi推送至callback queue ,eventloop轮询

    Promise有哪儿三种状态

    三种状态:
    • pending 过程中
    • resolved 成功 触发 then
    • rejected 失败 触发 catch

    状态变化是不可逆的

    状态的表现和变化

    then 和 catch 改变状态

    • then 正常返回一个resolved 的Promise, 如果有报错, 则返回一个 rejected 的Promise
    • catch正常返回一个resolved 的Promise, 如果有报错, 则返回一个 rejected 的Promise

    async await 语法

    • 异步回调 callback hell
    • Promise then catch 链式调用,但也是基于回调函数

    async await 是同步语法去编写异步代码,彻底的消灭了回调函数

    async 相当于封装了Promise 又返回一个Promise

    await 相当于 Promise的then

    async await和Promise的关系

    • Async Await是消灭异步回调的终极武器
    • 但是和Promise并不互斥
    • 两者是相辅相成的

    执行Async函数,返回的是一个Promise , 无论返回什么,都会封装成一个Promise对象

    await相当于Promise的then()

    try...catch 替代了Promise的catch

    异步的本质

    • Async Await是消灭异步回调的终极武器
    • JS还是单线程,该异步还要异步,还是基于event-loop来实现的
    • Async Await 只是个语法糖,但是这个糖好吃
    • Async Await 只是语法层面像同步的写法,但本质脱离不了异步
    async function async1 () {
     console.log('async1 start')
     await async2() // await 后面所有的语法 都可以当成callback执行
     console.log('async1 end') *// 关键在这一步,它相当于放在 callback 中,最后执行*
    }
    async function async2 () {
     console.log('async2')
    }
    
    console.log('script start')
    async1()
    console.log('script end')
    

    你猜猜打印的顺序~~~~ 异步的本质!

    for ...of 的应用场景

    • for ... in forEach 会同时执行遍历,因为属于同步语法

    • for ... of 常用在异步的遍历

      第一次遍历有结果后才会执行第二次遍历

    宏任务 macro Task,微任务micro Task(event-loop事件 异步)

    什么是宏任务 macro Task,微任务micro Task

    • 宏任务 > setTimeout setInterval ajax DOM事件

    • 微任务 > Promise async await

      微任务的执行时机比宏任务要早

    event-loop 和 dom渲染

    为什么微任务执行时机比宏任务要早

    DOM渲染时机:

    1. 第一次同步代码全部执行完,执行栈(call stack)空闲, 会尝试DOM渲染 , 然后才会执行 event-loop机制

      1. 每次轮询结束一次之后,DOM结构如果有变化的话, 会再次尝试DOM渲染
        3. 再次触发下一次的 event - loop

    微任务 宏任务的区别

    宏任务 : DOM渲染后触发 setTimeout

    微任务 :DOM渲染前触发 Promise

    为什么微任务执行时机要比宏任务早

    Promise 是 ES6规范,不是W3C规范,它不会进入webapi 及 callback queue

    而是等待时机推入 mircro queue [微任务队列]

    所以 event-loop的执行步骤不一样

    1. call stack 清空
    2. 执行微任务
    3. 尝试DOM渲染
    4. event-loop
    5. 执行宏任务

    微任务是ES6语法规定的

    宏任务是由浏览器规定的

    总结:

    • event loop
    • Promise 进阶
    • async await
    • 微任务 宏任务

    JS-web-API

    • JS 基础知识 规定语法 ECMA 262标准
      • 变量类型计算
      • 原型和原型链
      • 作用域和闭包
    • JS Web API 网页操作的API W3C标准
      • DOM 网页节点
      • BOM 浏览器的事情(导航,url ,跳转)
      • 事件绑定
      • ajax
      • 存储
    • 前者是后者的基础,两者结合才能挣钱

    DOM的本质是什么

    Document Object Model

    vue 和 react 框架应用广泛,已经封装了Dom操作

    DOM操作是必备知识,不可不会,框架只是个框架

    vue 与 react 的底层也是在操作DOM节点

    DOM 的本质 : 从html语言解析出来的一棵树~

    所以叫 DOM 树

    DOM 节点操作

    获取DOM节点

    getElementById
    getElementByTagName
    getElementByClassName
    querySelectorAll
    

    attribute

    直接修改标签的属性,会改变html结构
    getAttribute('')
    setAttribute('style','font-size:50px;')
    

    property

    纯操DOM 修改js变量,不会体现到html结构中
    let p = document.getElementById('p')
    p.style.width = '100px'
    p.style.color = '100px'
    p.calssName = ''
    p.nodeName
    p.nodeType
    
    • 两者都能引起DOM的重新渲染

    DOM 结构操作

    新增节点

    let div1 = document.getElementById('div1')
    let p1 = document.createElement('p')
    p1.innerHtml = '<p>this is p1</p>'
    div1.appendChild(p1)
    

    移动节点

    对现有div 插入已存在节点,会移动此节点
    

    获取子元素列表

    let div1 = document.getElementById('div1')
    div1.childNodes
    

    过滤获取的子元素

    let div1 = document.getElementById('div1')
    
    const divChildP = Array.prototype.slice.call(div1.childNodes).filter((child)=>{
    	if(child.NodeType === 1){
    		return true
    	}
    	return false
    })
    
    console.log(divChildP)
    

    删除子元素

    div1.removeChild( divChildP[0] )
    

    获取父元素

    p1.parentNode
    

    DOM 性能

    如何优化DOM性能

    • DOM的操作非常昂贵,要避免频繁的操作DOM

    • 对DOM查询做缓存

      • 缓存length

        let dd = document.getElementByTagName('div')
        let length = dd.length
        for(let i = 0 ; i< length ; i++){
            对length进行缓存
        }
        
    • 将多次操作改为一次操作

      创建一个文档片段
      let frg = document.createDocumentFragment()
      将需要插入的内容 appendchild 到fragment中
      fragment.appendchild(items)
      div1.appendchild(fragment)
      

    面试题:

    DOM是什么数据结构?

    DOM操作的常用API?

    attribute 和 property 的区别?

    一次性插入多个DOM,考虑性能?

    JS-WEB-API-BOM

    Browser Object Model

    • 如何识别浏览器的类型
    • 分解拆解url的各个部分

    知识点

    • navigator.userAgent ( ua ) 拿到浏览器的信息
    • screen 屏幕信息
    • location 地址信息 url的信息
      • location.herf 整个url
      • location.protocol 请求协议 http/https
      • location.host 域名
      • location.search 常用信息
      • location.hash #号后面的内容
      • location.pathname 浏览器路径(/后的内容)
    • history 前进后退信息
      • history.back 后退
      • history.forward 前进

    JS-WEB-API-事件

    知识点:

    事件绑定
    const div = document.getElementById('xx')
    div.addEventListener('click',(event)=>{
    	console.log('click')
    })
    
    事件冒泡
    const div = document.getElementById('xx')
    div.addEventListener('click',(event)=>{
    	event.stopPropagation()  阻止冒泡
    	console.log('冒泡')
    })
    
    const body = document.body
    body.addEventListener('click',(event)=>{
    	console.log('body冒泡')
    })
    

    event.prevenDefault() //阻止默认行为

    event.stopPropagation() 阻止冒泡

    事件代理

    什么是事件代理

    把事件绑定到不好绑定或者没法绑定元素的父元素上
    只在父元素上绑定一个事件,处理子元素的事件
    
    面试题
    • 编写一个通用的事件监听函数

      function bindEvent (elem , type , fn ){
      	elem.addEventListener(type, fn)
      }
      
      let dd = document.getElementById('xx')
      bindEvent(dd,'click',event => {
      	event.target 		  //获取当前被绑定对象
      	event.prevenDefault() //阻止默认行为
      	event.target.matches('a') 		  //判断是否包含a标签
      	alert('clicked')
      })
      

      进化版事件监听,增加过滤条件

      // 通用的事件绑定函数
      // function bindEvent(elem, type, fn) {
      //     elem.addEventListener(type, fn)
      // }
      function bindEvent(elem, type, selector, fn) {
          if (fn == null) {
              fn = selector
              selector = null
          }
          elem.addEventListener(type, event => {
              const target = event.target
              if (selector) {
                  // 代理绑定
                  if (target.matches(selector)) {
                      fn.call(target, event)
                  }
              } else {
                  // 普通绑定
                  fn.call(target, event)
              }
          })
      }
      
    • 描述事件冒泡的流程

      事件会随着触发元素向上冒泡   最高body,   所以才可以实现  事件代理
      
    • 无限下拉图片列表(瀑布式),如何监听每个图片的点击 ?

      1. 事件代理
      2. target 获得触发元素
      3. matches 来判断是否为触发元素
      

    JS-WEB-API-Ajax

    知识点:XMLHttpRequest

    GET

    const xhr = new XMLHttpRequest()
    //	 是否异步处理  false 否 
    xhr.open('GET',"/api",true)
    xhr.onreadystatechange = function(){
    	if(xhr.readyState === 4){
    		if(xhr.stats === 200){
    			JSON.parse(xhr.responseText) //转换为json格式
    			alert(xhr.responseText)
    		}
    	}
    }
    xhr.send(null)
    

    POST

    const user = {
    	username : 'xxx'
    	password : '123'
    }
    const xhr = new XMLHttpRequest()
    //	false 为异步处理
    xhr.open('POST',"/api",false)
    xhr.onreadystatechange = function(){
    	if(xhr.readyState === 4){
    		if(xhr.status === 200){
    			JSON.parse(xhr.responseText) //转换为json格式
    			alert(xhr.responseText)
    		}
    	}
    }
    xhr.send(JSON.stringfly(user))
    

    知识点:状态码

    • readyState
      • 0 init
      • 1 readysend
      • 2 sending
      • 3 decode
      • 4 ok
    • status
      • 2xx sccuess
      • 3xx redirect
        • 301 always redirect
        • 302 temp redirect
        • 304 use cache to reload
      • 4xx error
        • 404 errurl or has no auth to visit
        • 405
      • 5xx Server error

    知识点:跨域:同源策略,跨域解决方案

    什么是同源策略

    !浏览器要求当前网页和Server端必须同源 
    

    同源 : 域名,协议,端口必须一致

    图片 CSS JS 无视跨域

    • 可以实现统计打点

    • 可以使用CDN,CDN一般为外域
  • 相关阅读:
    【poj2478-Farey Sequence】递推求欧拉函数-欧拉函数的几个性质和推论
    【poj1284-Primitive Roots】欧拉函数-奇素数的原根个数
    【hdu2815-Mod Tree】高次同余方程-拓展BadyStepGaintStep
    【poj3243-Clever Y】高次同余方程-拓展BabyStepGiantStep
    数论之高次同余方程(Baby Step Giant Step + 拓展BSGS)
    POJ1094-Sorting It All Out
    POJ-2299 Ultra-QuickSort
    NYOJ542-试制品
    POJ1936-All in All
    POJ3080-Blue Jeans
  • 原文地址:https://www.cnblogs.com/maozhe/p/13116400.html
Copyright © 2020-2023  润新知