美文网首页
JS基础课程总结 - 题目

JS基础课程总结 - 题目

作者: 木头就是我呀 | 来源:发表于2020-04-03 11:26 被阅读0次

    变量类型和计算

    • typeof能判断哪些类型
      1. 能判断所有的值类型
          字符串(string)、数值(number)、布尔值(boolean)、undefined、null、symbol
      2. 能判断函数
      3. 能判断是不是引用类型(无法细分),想细分怎么办?使用instanceof
    
    • 何时使用 === 何时使用 ==
      1. 除了==null外  其余的都要用===
    
    • 值类型引用类型的区别
      1. 堆栈的角度去判断
    
    • 手写深拷贝
      function deepClone(obj) {
          if(obj == null || typeof obj !== 'object'){
            return obj
          }
          let result = null;
          if(obj instanceof Array){
              result = []
          }else{
              result = {}
          }
          for(let key in obj){
              result[key] = deepClone(obj[key])
          }
          return result
      }
    

    原型和原型链

    • instanceof 的本质
      对象a由函数A创建,当使用```a instanceof A```的时候,会出现:a顺着__proto__往上找,A顺着prototype往上找,如果两者在同一个地方相遇,即返回true。
    
    • 如何判断一个变量是不是数组
      1. arr instaceof Array
      2. Array.isArray
      3. Object.prototype.toString.call(arr)
    
    • 手写一个简易的jQuery,考虑插件,考虑拓展性
      class jQuery {
        constructor(selector){
            let dom = document.querySelectorAll(selector)
            const length = dom.length
    
            for(let i=0;i<length;i++){
                this[i] = dom[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){
            this.each(elem=>{
                elem.addEventListener(type,fn,false)
            })
        }
    
        // 拓展api
    }
    
    /**
     let divs = new jQuery('div')
     divs.each(div=>{
            console.log(div);
        })
     divs.on('click',(e)=>{
            console.log(e);
        })
     console.log(divs.get(1));
     */
    
    // 插件机制
    jQuery.prototype.dislog = function () {
        // 添加插件
    }
    
    // 复写(造轮子)
    class myJQuery extends jQuery{
        constructor(selector) {
            super(selector);
    
        }
        // 拓展自己的方法
        // ...
    }
    
    • extends的本质,怎么理解
    例如:B extends A
      实现:B._ _ _proto_ _ _ = A       B.prototype._ _ _proto_ _ _ = A.prototype  
    

    作用域和闭包

    • this的不同应用场景,如何取值
        1. 构造函数(this -> 当前对象)
        2. 函数作为对象的一个属性
        let obj = {
            aa:111,
            b:function () {
                console.log(this);
            }
        }
        obj.b()
    
    • 手写bind/call/apply函数
        function a(args) {
            console.log(this);
            console.log('aaa',args);
        }
    
        let b = {
            aaa:111
        }
    
        Function.prototype.myBind = function () {
            let args = [...arguments]
            let context = args.shift()
    
            let _this = this
            return function () {
                _this.apply(context,arguments)
            }
        }
    
        // a.myBind(b,[1,2,3])()
    
        Function.prototype.myCall = function () {
            let args = [...arguments]
            let context = args.shift()
            context.fn = this
            const result = context.fn(...args)
            delete context.fn
            return result
        }
        a.myCall(b,1,2,3)
    
        // a.apply(b,[1,2,3])
        Function.prototype.myApply = function () {
            let args = [...arguments]
            let context = args.shift()
    
            context.fn = this
            let result = context.fn(args)
            delete context.fn
            return result
        }
        a.myApply(b,[1,2,3])
    
    • 实际开发中闭包的应用场景,举例说明
        1. 封装变量,将其封装到函数内部,不让拿到原值进行修改(绑到函数的原型上面,感觉更好)
        2. 模拟块级作用域(立即执行函数)
        3. 缓存数据
         let numCache = function () {
            var cache = {}
            return function () {
                var arg = JSON.stringify(arguments)
                if(cache[arg]){
                    // 从cache中取出
                    console.log('从cache中取出');
                }else{
                    // 计算
                    console.log('计算');
                    let sum = 0
                    for(let i=0;i<arguments.length;i++){
                        sum+=arguments[i]
                    }
                    cache[arg] = sum
                }
            }
        }
    
        let sum = numCache()
        sum(1,2,3) // 计算
        sum(1,2,3) // 从cache中取出
    
    • 创建10个<a>标签,点击的时候弹出来对应的序号(let,闭包)
        let dom = document.getElementById('myDiv')
        let df = new DocumentFragment()
        for (var i=0;i<10;i++){
            let node = document.createElement('a')
            node.innerHTML = 'node '+i
            let fn = function(){
                var index = i
                return function () {
                    console.log(index);
                }
            }
    
            /**
             * 如果不使用闭包,在onclick的时候,此时执行的函数中的i不存在当前函数执行上下文中,就会向父级作用域(global)查找,找到的i=10
             * 使用闭包,在onclick的时候,此时执行函数中的i不存在当前执行函数上下文中,就会向父级作用域(fn)查找,找到了,此时父级作用域中
             * 的i是在fn函数声明的时候就创建了,因为作用域是词法环境导致,即函数声明时得到作用域,所以fn中的i就是循环时候的每次都不一样的i,
             * 所以找到父级作用域(fn)时,得到的i就是想要的结果。
             * */
    
            node.onclick = fn()
    
            /**
             * 简单写法
             * node.onclick = (function(i){
                return function () {
                    console.log(i);
                }
            })(i)
             */
    
            df.append(node)
        }
        dom.append(df)
    

    异步和单线程

        function loadImg() {
            return new Promise((resolve, reject) => {
                let img = document.createElement('img')
                img.src = url
                img.onload = function () {
                    resolve(img)
                }
                img.onerror = function (err) {
                    reject(err)
                }
            })
        }
    
    • 前端使用异步的场景有哪些
      1. 网络请求  
      2. 定时任务
    

    DOM

    • DOM是哪种数据结构
      - 树
    
    • DOM本质是什么
      - 一棵html树
    
    • DOM操作常用的API
    - 节点操作  
      - 查询节点 
        getElementById / getElementsByTagName / getElementsByClassName / querySelectorAll
      - 插入节点 
         appendChild...
      - 移动节点 
        appendChild() 将现有节点插入到其他内部,会出现移动的效果
    
    • attributeproperty区别是什么
      property : p1.style.width...... // 修改js变量属性,不会体现到html中 (建议)
      attribute : p1.setAttribute('data-name',111)   // 修改html属性,直接改变html结构
    
    • 一次性插入多个DOM节点,考虑性能
      - DocumentFragement
      - length的时候,赋给一个变量
    

    BOM

    • 如何识别浏览器的类型
      - 获取浏览器的信息
        - navigator      / userAgent   
    
      - 获取屏幕的信息
        - screen  / width height
    
      - 获取地址栏的信息
        - location  href/protocol/pathname/search/hash
    
      - 前进后退的信息
        - history  /forward() back() 
    
    • 拆解URL的各个部分

    事件

    • 编写一个通用事件监听函数
        function bindEvent(element, type, selector, fn) {
            // selector是事件代理时候用
            if(fn == null){
                fn = selector
                selector = null
            }
    
            element.addEventListener(type,function(event){
                const target = event.target
    
                if(selector){
                    // 代理绑定
                    if(target.matches(selector)){
                        // dom是否符合selector选择器
                        fn.call(target,event)
                    }
                }else{
                    //普通绑定
                    fn.call(target,event)
                }
            })
        }
    
    • 描述事件冒泡的流程
     以点击事件为例,用户点击div的时候,会触发div的点击事件监听函数,接着会触发div的父级dom的点击事件监听函数,
    一直往上冒,冒到document为止
    
    • 无限下拉的图片列表,如何监听每个图片的点击
      - 使用事件代理,使用父级监听点击函数,然后判断即可。不要每个元素都添加。
    
    • 事件代理
    子元素比较多,不需要挨个进行事件绑定,将其事件绑定到父元素上,然后做一些判断即可。
      - 优点
        代码简洁 、 减少浏览器内存占用 、 不要滥用
    

    ajax

    • 手写一个简易的ajax
        let xhr = new XMLHttpRequest()
        xhr.onreadystatechange = function () {
            // 0: 请求未初始化
            // 1: 服务器连接已建立
            // 2: 请求已接收
            // 3: 请求处理中
            // 4: 请求已完成,且响应已就绪
            if(xhr.readyState === 4){
                if(xhr.status === 200){
                    console.log(JSON.parse(xhr.responseText));
                }
            }
        }
        xhr.open('get','./data.json')
        xhr.send()
    
    • 跨域常用的实现方式
      - jsonp 和 CROS(server做)
    
    • 哪些标签不跨域
      -<img>  <link>  <script>
    
    • fetch是什么
      一种异步请求的工具,不同于XMLHttpRequest,是一种新的api,底部实现Promise,
    有一个缺点就是返回的promise不会被标记为reject,即使HTTP相应的状态码是404或者500.
    

    存储

    • 描述cookie,localStorage,sessionStorage的区别(cookie的本质
    cookie的本质:
      - 本身是用于浏览器和server通讯,不是用于本地存储,只是被借用来本地存储。前后端都可以修改cookie。
    

    webpack相关

    - 为什么使用webpack
      ES6的模块化,浏览器是暂时不支持的。
      ES6语法,浏览器并不完全支持
      压缩代码,整合代码,以让网页加载更快(缓存机制)
    
    - 安装webpack
      ```npm install webpack webpack-cli -D  --代理```
    
    - babel的用处
      将ES6的语法转移为ES5的语法
    
    - 模块化的规范是什么
    
    // 多导出
    export function f() {}
    export const a = 111
    
    import {fn,a} from './a'
    
    // 单导出
    function f1() {}
    const aa = 222
    export {
        f1,aa
    }
    import {fn,aa} from "./a";
    
    // 导出多个,导入时不解构
    let aaa222 = {}
    export default aaa222
    
    import aaa222 from './'
    

    页面加载过程

    • 从输入url到渲染出页面的整个过程
    # 加载过程
    1. DNS(Doman name server)解析:域名 -> IP
    2. 浏览器根据IP地址向服务器发起HTTP请求
    3. 服务器接处理HTTP请求,并返回给浏览器
    
    # 渲染过程
    1. 根据HTML代码生成DOM Tree
    2. 根据CSS代码生成CSSOM (CSS 对象模型)
    3. 将DOM Tree和CSSOM 整合生成 Render Tree
    4. 根据Render Tree渲染页面
    5. 遇到script的话 就暂停渲染  有限执行js代码  因为js线程和渲染线程是一个线程
    6. 直至把Render Tree渲染完成
    
    • 为何把css放在head中
    扫描到head后,发现没有css,此时就去渲染页面,到后面发现css后,可能会修改之前渲染的,
    所以会做重复工作,甚至造成页面跳动等情况。
    
    • window.onloadDOMContentLoaded的区别
        window.addEventListener('load',function () {
            // 网页上所有资源都加载完才会触发,包括耗时的图片等...
        })
        window.addEventListener('DOMContentLoaded',function () {
            // DOM渲染完毕即可执行,此时的图片、视频还可能都没有加载完
        })
    

    性能优化

    • 前端常见的性能优化的方案
    # 性能优化
    原则: 空间换时间
        1. 多使用内存,缓存或者其他方法
        2. 减少CPU的计算量,减少网络加载耗时
    从何入手:
        让加载更快
            减少资源体积 - 压缩代码
            减少访问次数
                合并代码(合并js等资源)
                SSR服务端渲染(把资源在后端一次组装完成,减少客户端的请求次数)
                缓存(静态资源加hash后缀,根据文件计算hash。文件不变,则会自动触发http缓存机制,返回304)
            使用更快的网络 - CDN
        让渲染更快
            CSS放在head,JS放在body最下面
            尽早开始执行JS,在DOMContentLoaded触发
            懒加载(图片懒加载,上滑加载更多...)
            对DOM查询进行缓存
            避免频繁的DOM操作,使用DocumentFragement片段
            节流、防抖
    
    • 手写节流防抖
      防抖,节流的意思
      防抖:频繁操作,最后XXms后触发
      节流:频繁操作,按一定频率触发
    
        // 节流
        // 主要思想: 在频繁的回调函数中,每XXms就执行一次,平均速率
        function throttle(fn,delay = 500) {
            let timer = null
            return function () {
                if(timer){
                    return
                }
    
                timer = setTimeout(()=>{
                    fn.apply(this,arguments)
    
                    timer = null
                },delay)
            }
        }
        input.oninput = throttle(function (e) {
            console.log(e);
        },1000)
    
        // 防抖 - 最后触发
        // 主要思想: 在用户停止输入的那一瞬间开始,倒数XXms
        function debounce(fn, delay = 1000) {
            let timer = null
    
            return function () {
                if(timer){
                    clearTimeout(timer)
                }
                timer = setTimeout(()=>{
                    fn.apply(this,arguments)
                    timer = null
                },delay)
            }
        }
        input.oninput = debounce(function (e) {
            console.log(e);
        },1000)
    
        
    

    安全

    • Web前端常见的安全攻击方式预防
    常见的攻击方式
      - XSS  &  XSRF
      - XSS 发表博客,嵌入<script>脚本,拿到别人的cookie信息
        解决方案:更换特殊字符<、>等等
      - XSRF 跨站请求伪造  <img src=xxx.com/pay...../>
        解决方案:使用post请求  &  增加验证(密码,验证码等等)
    

    面试真题

    1. var let const的区别
    
        var 是ES5的语法  , let const是ES6的语法 ; var 有变量提升
        var和let是变量 可以修改,const是常量,不可修改
        let const有块级作用域,var没有
    
    2. typeof 能判断那些数据类型
    
        值类型:string,number,boolean,undefined,symbol
        引用类型:object(注意,typeof null === 'object' <- null是值类型,但是浏览器bug)
        函数:function
    
    3. 列举 强制类型转换 & 隐式类型转换
    
        强制:parseInt parseFloat toString等
        隐式:if 、 逻辑运算 、 == 、 +拼接字符串
    
    4. 手写深度比较 isEqual
    
        function isObject(obj) {
            return typeof obj === 'object' && obj !== null
        }
    
        function isEqual(obj1,obj2) {
            // 不是对象  就直接返回两者三等
            if(!isObject(obj1) || !isObject(obj2)){
                return obj1 === obj2
            }
            if(obj1 === obj2){
                return true
            }
    
            // 两个都是对象或者数组 而且不相等
            let obj1keys = Object.keys(obj1)
            let obj2keys = Object.keys(obj2)
    
            if(obj1keys.length !== obj2keys.length){
                return false
            }
    
            // 两个都是对象或者数组 而且keys个数一致
            // 以obj1为基准  进行比较
            for(let key in obj1){
                let result =  isEqual(obj1[key],obj2[key])
                if(!result){
                    return false
                }
            }
            return true
        }
    
    5. split() 和 join() 的区别
    
        split是拆分字符串,join是拼接数组,两者完全背离
    
    6. 数组常见API
    
    ---1.连接两个或更多的数组。
    ---2.检测数组元素的每个元素是否都符合条件。
    ---3.检测数组元素中是否有元素符合指定条件。
    ---4.反转数组的元素顺序。
    ---5.检测数组元素,并返回符合条件所有元素的数组。
    ---6.删除并返回数组的第一个元素。
    ---7.搜索数组中的元素,并返回它所在的位置。
    ---8.用于插入、删除或替换数组的元素。
    ---9.对数组的元素进行排序。
    ---10.删除数组的最后一个元素并返回删除的元素。
    ---11.把数组的所有元素放入一个字符串。
    ---12.把数组转换为字符串,并返回结果。
    ---13.向数组的末尾添加一个或更多元素,并返回新的长度。
    ---14.返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
    ---15.通过指定函数处理数组的每个元素,并返回处理后的数组。
    ---16.选取数组的的一部分。
    ---17.返回数组对象的原始值。
    ---18.向数组的开头添加一个或更多元素,并返回新的长度。
    ---19.数组求和
        1.concat() 不
        2.every() 不
        3.some() 不
        4.reverse() 会
        5.filter() 不
        6.shift() 会
        7.indexOf() 不
        8.splice() 会
        9.sort() 会
        10.pop() 会
        11.join() 不
        12.toString() 不
        13.push() 会
        14.lastIndexOf() 不
        15.map() 不
        16.slice() 不
        17.valueOf() 不
        18.unshift() 会
        19.reduce((total,currentValue)=>{})
    
    7. 数组slice和splice的区别是什么
    
        slice是 切片
        splice是 剪切
            splice(1,3,x,x,x)
            从下标为1开始,后截三位,替换成x,x,x,并返回截出来的值,为数组
    
    8. [10,20,30].map(parseInt)
    
        将其拆分开,就得到:
        [10,20,30].map((item,index)=>{
            // 注意parseInt的第二个参数,是代表进制
            return parseInt(item,index)
        })
    
    9. 函数call和apply的区别
    
        就在参数上是否是数组
    
    10. 事件代理(委托)是什么
    
        冒泡事件,无限下拉的点击事件监听
    
    11. 闭包是什么?有什么特性?有什么负面影响?
        闭包就是能够读取其他函数内部变量的函数
    
        函数作为参数被传入,函数作为返回值被返回
        理解 " 自由变量 " 是什么?
            就是当前函数内找不到定义的变量,在父级作用域内,该变量就是自由变量
        影响:
            变量常驻内存,得不到释放,但不一定是内存泄漏(内存泄漏是不用的内存无法被回收,闭包占用的内存可能会使用)
    
    12. 如何阻止" 事件冒泡 " 和 " 默认行为 "
    
        阻止冒泡:e.stopPropagation()
        取消默认行为:e.preventDefault()
    
    13. jsonp的原理
    
        通过script标签实现的
        1. 在window上绑定一个逻辑函数
        window.callback = function(data){
            console.log(data)
        }
        2. 请求一个js资源,js资源里面有一个执行函数,callback({一些数据作为入参传递进来})
    
    14. load 和 ready的区别
    
        load 是所有资源加载完毕
        ready => DOMContextLoaded 是dom加载完毕就会触发
    
    15. 函数声明和函数表达式的区别
    
        函数声明:在执行前预加载,类似代码提升
        函数表达式:不会
    
    16. new Object() 和 Object.create()的区别
    
        {} === new Object({}) 原型是Object.prototype
        Object.create(null) 没有原型
        Object.create({xxx}) 可以指定原型
        Object.create({xxx}) 把传入的对象赋值到__proto__上
    
    17. 正则表达式
        // 字符串 字母开头,后面数字字母下划线,长度6-30
    
        /^[a-zA-Z]\w{5,29}$/
    
        // 邮政编码
    
        /^\d{6}$/
    
        // 小写英文字母
    
        /^[a-z]+$/
    
        // 英文字母
    
        /^[a-zA-Z]+$/
    
        // 日期格式
    
        /^\d{4}-\d{1,2}-\d{1,2}$/
    
        // 用户名
    
        /^[a-zA-Z]\w{5,29}$/
    
        // 简单ip地址匹配
    
        /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
    
    18. 手写trim方法,保证兼容性
    
        String.prototype.trim = function () {
            return this.replace(/^\s+/,'').replace('/\s+$/','')
        }
    
    19. 获取数组的最大值
        1. 将arguments变为数组,除了解构外,还有什么办法
            let arr = Array.prototype.slice.call(arguments)
        2. 使用原生获取最大值的方法
            Math.max(n1,n2,n3...)
            Math.min(n1,n2,n3...)
    
    20. 如何使用JS实现继承
    
        class继承
        prototype继承(不推荐)
    
    21. 如何捕获JS程序的异常
    
        手动:try{}catch(e){}
        自动:window.onerror = function(){
            // 对跨域的js,cdn等,不会有详细
            // 对于压缩的js,还需要配合 sourceMap 去反查询压缩的行列
        }
    
    22. 什么是JSON
    
        就是一种数据格式,本身是一段字符串
        格式和js对象解构一致,比较友好
    
    23. 怎么得到浏览器参数
    
        function query(name) {
            let search = location.search.substr(1)
            let reg = new RegExp(`(^|&)${name}=([^&]*)($|&)`)
            let res = search.match(reg)
            if(!res){
                return null
            }
            return res[2]
        }
    
    24. 数组拍平
        let arr = [1,2,[1,2]]
        Array.prototype.concat.apply([],arr)  // 两层
        function flat(arr) {
            let isDeep = arr.some(item=>item instanceof Array)
            if(!isDeep){
                return arr
            }
            let res = Array.prototype.concat.apply([],arr)
            return flat(res)
        }
    
        console.log(flat([1, 2, [3, 4, [1, 2, [3, 4]]]]));
    
    25. 数组去重
    
        传统方式
            挨个比较
            function clear(arr){
                let result = []
                arr.forEach(a=>{
                    if(!result.includes(a)){
                        result.push(a)
                    }
                })
                return result
            }
    
        使用Set
            new Set([1,1,2,3,1])  // 1,2,3
    
    26. 介绍一下RAF requestAnimationFrame
        动画的一个api,动画流畅的必要条件:60帧/s,使用setTimeout的话,需要手动控制,但是RAF是自动计算的
        window.requestAnimateFrame(fn)
        切换tab页面的时候,动画是暂停的,浏览器做了优化
    
    27. Object.assign()是深拷贝吗?
        不是的,只是浅层级被拷贝了,深层级没有
    

    相关文章

      网友评论

          本文标题:JS基础课程总结 - 题目

          本文链接:https://www.haomeiwen.com/subject/yjycphtx.html