美文网首页
前端JavaScript面试技巧

前端JavaScript面试技巧

作者: 读书的鱼 | 来源:发表于2019-02-27 19:10 被阅读0次

    第5章 JS-Web-API(上)

    从基础知识到JSWebAPI

    下面来进行一个抛砖引玉
    回顾JS基础知识
    1.变量类型和计算
    2.原型和原型链
    3.闭包和作用域
    4.异步和单线程
    5.其他(如日期、Math、各种常用API)
    特点:表面看来并不能用于工作开中发代码
    内置函数:Object Array Boolean String...
    内置对象:Math JSON
    我们连在页面弹出一句hello world都不能实现

    JS基础知识:ECMA 262标准
    JS-Web-API:W3C标准

    那么JS-Web-API究竟做了些什么呢?
    W3C标准中关于JS的规定有:
    1.DOM操作
    2.BOM操作
    3.事件绑定
    4.ajax请求
    5.存储

    JS-Web-API
    没有规定任何JS基础相关的东西
    不管什么变量类型、原型、作用域和异步
    只管定义用于浏览器中JS操作页面的API和全局变量(window、document、navigator等等)

    总结:
    常说的JS(浏览器执行的JS)包含两部分:
    JS基础知识(ECMA262标准)
    JS-Web-API (W3C标准)

    5-2 DOM本质

    DOM(Document Oject Module)
    题目
    DOM是哪种基本的数据结构?
    答:树
    DOM操作的常用API有哪些?
    答:
    获取DOM节点,以及节点的property和attribute
    获取父节点,获取子节点
    新增节点,删除节点
    DOM节点的attribute和property有什么区别?
    property 只是一个JS对象属性的修改和获取
    Attribute 是对html标签属性的修改和获取

    5-3 DOM节点操作

    获取DOM节点(有四种)

    //第一种”元素“获取(getElementById)
    var div1 = document.getElementById('div')
    
    //第二种 集合获取(getElementsByTagName)
    var divList = document.getElementsByTagName('div')
    console.log(divList.length)
    console.log(divList[0])
    
    //第三种 集合获取(getElementsByClassName)
    var containerList = document.getElementsByClassName('.container')
    
    //第四种 集合获取(querySelectorAll)
    var pList = document.queryAelectorAll('p')
    

    property(属性,是DOM中 属性,是JavaScript里面的对象。例如:childNodes、firstChild)

    var pList = document.querySelectAll('p')
    var p = pList[0]  //获取的js对象
    console.log(p.style.width) //获取样式
    p.style.width = '100px' //修改样式
    console.log(p.className) //获取class
    p.className = 'p1' //修改 class
    
    //获取 nodeName 和 nodeType
    console.log(p.nodeName)
    console.log(p.nodeType)
    

    Attribute(特性:是html标签的特性,他的值只能够是字符串。例如:id、class、title、align)

    var pList = document.querySelectorAll('p')
    var p = pList[0]
    
    p.getAttribute('data-name')
    p.setAttribute('data-name','color-red')
    p.getAttribute('style')
    p.setAttribute('style','font-size:12px')
    
    5-4 DOM结构操作

    1.新增节点
    创建节点==》给创建的节点赋值==》让创建好的节点放到哪个节点下面
    createElement('p') innerHTML appendChild
    2.获取父节点parentElement
    3.获取子节点childeNodes
    4.删除节点 removeChild()

    html Demo

    <div id="div1">
        <p id="p1">this is p1</p>
        <p id="p2">this is p2</p>
    </div>
    <div id="div2">
        <p id="p3">this is p3</p>
        <p id="p4">this is p4</p>
    </div>
    

    1.新增节点

    第一种是创建插入
    var p = document.createElement('p')
    p.innerHTML = 'new p'
    var div1 = document.getElementById('div1')
    div1.appendChild(p)
    
    第二种是存在的移动到已有的后面
    var p4 = document.getElementById('p4')
    var div1 = document.getElementById('div1')
    div1.appendChild(p4)
    

    2.获取父节点

    var p4 = document.getElementById('p4')
    var div1 = document.getElementById('div1')
    
    console.log(p4.parentElement)  //<div id="div2">...</div>
    console.log(div1.parentElement) //<body>...</body>
    

    3.获取子节点

    var div1 = document.getElementById('div1')
    console.log(div1.childNodes)
    
    console.log(div1.childNodes[0].nodeType)    //text   3
    console.log(div1.childNodes[1].nodeType)    //p       1
    console.log(div1.childNodes[0].nodeName)  //text   #text
    console.log(div1.childNodes[1].nodeName)  //p       p
    

    4.删除节点

    var div1 = document.getElementById('div1')
    var childNodes = div1.childNodes
    div.removeChild(childNodes[1])
    
    5-5 BOM操作

    BOM(Browser Object Module)
    题目
    如何检测浏览器的类型
    navigator

    var ua navigator.userAgent
    var isChrome = ua.indexOf('Chrome')
    console.log(isChrome) //true则是chrome浏览器
    

    screen

    console.log(screen.width)
    console.log(screen.height)
    

    拆解url的各部分
    location

    location.href
    location.protocol
    location.host
    location.pathname
    location.search
    location.hash
    

    history

    history.back()
    history.forward()
    

    第6章 JS-Web-API(下)

    6-1 事件-知识点

    题目
    1.编写一个通用的事件监听函数

    var btn = document.getElementById('btn1')
    btn.addEventListener('click',function(event){
          console.log('clicked')
    })
    
    function bindEvent(elem,type,fn){
        elem.addEventListener(type,fn)
    }
    var a = document.getElementById('link')
    bindEvent(a,'click',function(e){
      e.preventDefault() //阻止默认行为
      alert('clicked')
    })
    

    2.描述事件冒泡流程

    //html 部分
    <body>
      <div id="div1">
        <p id="p1">激活</p>
        <p id="p2">取消</p>
      </div>
    </body>
    
    //js 部分
    var p1 = document.getElementById('p1')
    var body = document.body
    bindEvent(p1,'click',function(e){
      e.stopPropatation() //阻止冒泡
      alert('激活')
    })
    bindEvent(body,'click',function(e){
      alert('取消')
    })
    

    代理

    html 部分
    <div id="div1">
      <a href="#">a1</a>
      <a href="#">a2</a>
      <a href="#">a3</a>
      ...
    </div>
    
    js 部分
    var div1 = document.getElementById('div1')
    addEvent(div1,'click',function(e){
      var target = e.target    //获取当前点击元素
      if(target.nodeName ==='A'){  //如果当前元素标签是a标签
        alert(target.innerHTML)
      }
    })
    

    完善通用绑定事件函数

    function bindEvent(elem,type,selector,fn){
        if(fn==null){
            fn = selector
            selector = null
        }
        elem.addEventListener(type, function(e){
            var target
            if(selector) {
                target = e.target
                if(target.matches(selector)){
                    fn.call(target,e)
                }else{
                  fn(e)
                }
            }
        })
    }
    
    
    //使用代理
    var div1 = document.getElementById('div1')
    bindEvent(div1,'click','a',function(e){
        console.log(this.innerHTML)
    })
    
    //不使用代理
    var a = document.getElementById('a1')
    bindEvent(div1,'click',function(e){
      console.log(a.innerHTML)
    })
    

    代理的好处
    代码简洁
    减少浏览器内存占用

    3.对于一个无限下拉加载图片的页面,如何给每个图片绑定事件
    答:采用2里面的代理就能实现

    6-2 Ajax-XMLHttpRequst

    题目
    1.手动编写一个ajax,不依赖第三方库
    知识点
    XMLHttpRequest

    var xhr = new XMLHttpRequest()
    xhr.open("GET","/api",false)
    xhr.onreadystatechange = function(){
        if(xhr.readState == 4){
            if(xhr.status == 200){
                alert(xhr.responseText)
            }
        }
    }
    xhr.send(null)
    

    状态码说明

    //readyState
    0-(未初始化) 还没有调用send方法
    1-(载入) 已经调用send()方法,正在发生请求
    2-(载入完成) send()方法执行完成,已经接收到全部响应内容
    3-(交互) 正在解析响应内容
    4-(完成) 响应内容解析完成,可以在客户端调用了
    
    //status 状态码说明
    2xx - 表示成功处理请求。 如 200
    3xx - 需要重定向,浏览器直接跳转
    4xx - 客户端请求错误,如404
    5xx - 服务器端错误
    

    2.跨域的几种实现方式
    什么是跨域
    浏览器有同源策略,不允许ajax访问其他域端口
    跨域条件:协议、域名、端口,有一个不同就算跨域
    http 80
    https 443
    可跨域的三个标签
    <img src="http://www.baidu.com/images/1.jpg" />
    <link href="" />
    <script src="" ></script>
    三个标签的场景
    img用于打点统计,统计网站可能有其他域
    link script 都可以使用CDN,CDN的也是其他域
    <script> 可以用于JSONP
    跨域注意事项
    所有的跨域请求都必须经过信息提供方允许
    如果未经允许即可获取,那是浏览器同源策略出现漏洞
    JSONP实现原理

    <script>
      window.callback = function(data){
        //这是跨域得到的信息
        console.log(data)
      }
    </script>
    <script src="http://www.baidu.com/api.js"></script>
    //以上返回 callback({x:100,y:200})
    

    服务器端设置http header

    response.setHeader("Access-Control-Allow-Origin","http://a.com,http://b.com");
    response.setHeader("Access-Control-Allow-Headers","x-Requested-With");
    response.setHeader("Access-Control-Allow-Methods","POST,GET,PUT,DELETE,OPTIONS");
    
    //接受跨域的cookie
    response.setHeader("Access-Control-Allow-Credentials","true")
    
    6-3 存储

    题目:
    描述一下cookie,sessionStorage,locationStorage的区别
    容量
    是否会携带到ajax中
    API易用性

    cookie
    本身用于客户端和服务器端通讯
    但是它有本地存储的功能,于是就被“借用”
    使用document.cookie = ... 获取和修改即可

    缺点
    存储量太小,只有4kb
    所有 http请求都带着,会影响获取资源的效率
    API简单,需要封装才能使用 document.cookie = ...

    localStorage和sessionStorage
    html5朱门为存储而设计,最大容量5M
    API简单易用
    localStorage.setItem(key,value)
    localStorage.getItem(key)
    坑:
    IOS safari 隐藏模式下
    localStorage.getItem 会报错
    建议:
    统一使用try-catch封装

    第7章 开发环境

    7-1 开发环境介绍

    IDE(写代码的效率)
    webstorm
    sublime
    vscode
    atom
    插件 插件 插件!!!

    7-2 Git

    git(代码版本管理,多人写作开发)
    正式项目都需要代码版本管理
    大型项目需要多人协作开发
    GIt和linux是一个作者

    平时自己练习可以用下面两个
    github、码云、码市等等

    常用命令
    git init //初始化.git
    git add .
    git checkout xxx //还原某个文件
    git commit -m "xxx" //备注
    git push origin master //推送到远程仓库
    git pull origin master //从远程更新代码

    git branch // 查看分支
    git checkout -b xxx / git checkout xxx //创建且切到该分支 / 切到某分支
    git merge xxx //合并某分支到该分支上

    7-3 JS模块化

    知识点
    1.不适用模块化的情况

    //util.js
    function getFormateDate(date,type){
      //type === 1 返回2017-06-15
      //type === 2 返回2017年06月15日
      //....
    }
    
    //a-util.js
    function aGetFormatDate(date){
      return getFormateDate(date)
    }
    
    //a.js
    var dt = new Date()
    console.log(aGetFormatDate(dt))
    

    那我们页面上引用就需要

    <script src="util.js"></script>
    <script src="a-util.js"></script>
    <script src="a.js"></script>
    

    那么如果这样使用就暴露出来了几个弊端:

    a.js顺序不能更改
    b.使用代码中的函数必须是全局变量,才能暴露给对方使用,全局变量污染
    c. a.js 知道引用a-util.js,但是它知道还需要依赖util.js吗?
    

    2.使用模块化
    针对上面的弊端我们有一个模块化的一个设想:

    //util.js
    export {
      getFormateDate(date,type){
          //type === 1 返回2017-06-15
          //type === 2 返回2017年06月15日
          //....
      }
    }
    
    //a-util.js
    var getFormateDate = require('util.js')
    export {
        aGetFormatDate(date){
              return getFormateDate(date)
         }
    }
    
    //a.js
    var aGetFormatDate = require('a-util.js')
    var dt = new Date()
    console.log(aGetFormatDate(dt))
    

    这样的话,自己需要的方法自己引入,使得依赖关系自动引入
    函数和函数之间的调用,没有必要是全局变量,解决全局变量污染的问题
    3.AMD
    require.js
    全局define函数
    全局require函数
    依赖JS会自动、异步加载
    下面是require.js 实现方式:

    //util.js
    define(function(){
      return {
          getFormatDate: function(date,type){
              if(type===1){
                return '2018-06-12'
              }
              if(type === 2){
                return '2018年06月12日'
              }
          }
       }
    })
    //a-util.js
    define(['util.js'],function(util){
      return {
        aGetFormatDate: function(date){
            return util.getFormatDate(date,2)
        }
       }
    })
    //a.js
    define(['a-util.js'],function(aUtil){
      return {
          printDate: function(date){
            console.log(aUtil.aGetFormatDate(date))
          }
       }
    })
    //main.js
    require(['a.js'], function(a){
      var dt =  new Date()
      a.printDate(dt)
    })
    

    那页面怎么引用呢?

    <script src="/require.min.js" data-main="./main.js"></script>
    

    4.CommonJS
    nodejs模块化规范,现在被前端大量采用,原因:
    前端开发依赖的插件和库,都可以从npm中获取
    构建工具的高度自动化,使得使用npm的成本非常低
    CommonJS不会异步加载,而是同步一次性加载出来

    5.AMD和CommonJS的使用场景
    需要异步加载JS,使用AMD
    使用了npm之后,建议只用CommonJS

    ## 7-4 打包工具

    grunt
    gulp
    webpack

    //webpack.config.js
    const path = require('path');
    const htmlWebpackPlugin = require('html-webpack-plugin');
    const cleanWebpackPlugin = require('clean-webpack-plugin');
    const webpack = require('webpack');
    
    module.exports = {
        mode: 'development',
        devtool: 'cheap-module-eval-source-map', //production: cheap-module-source-map
        // entry:'./index.js',
        entry: {
            main: './src/index.js',
            // sub:'./index.js'
        },
        devServer: {
            contentBase: './dist',
            port: 8081,
            open: true,
            hot: true,
            hotOnly: true
        },
        module: {
            rules: [{
                test: /\.(jpg|png|gif)$/,
                use: {
                    loader: 'url-loader', //file-loader
                    options: {
                        //placeholder 占位符
                        name: '[path][name].[ext]',
                        outputPath: 'images/',
                        limit: 1000
                    }
                }
            }, {
                test: /\.scss$/,
                use: [
                    'style-loader',
                    // 'css-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            importLoaders: 2,
                            // modules:true
                        }
                    },
                    'sass-loader',
                    'postcss-loader'
                ]
            }, {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'postcss-loader'
                ]
            }, {
                test: /\.(eot|svg|ttf|woff|woff2)$/,
                use: {
                    loader: 'file-loader'
                }
            }, {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                //如果options配置的内容比较多,那么就可以把options的内容放入到.babelrc文件中
                // options: {
                //  //下面注释的是针对babel/polyfill 来配置的
                //     // presets: [
                //     //     ['@babel/preset-env', {
                //     //         useBuiltIns: 'usage',
                //     //         targets:{
                //     //           chrome:'67' //只对大于chrome67这个版本上的进行补充,低于这个版本的话则不予处理,进而减小了打包文件的体积
                //     //         }
                //     //     }]
                //     // ]
    
                //     //下面这段针对的是plugin-transform-runtime 来配置的
                //     "plugins": [
                //         [
                //             "@babel/plugin-transform-runtime",
                //             {
                //                 "corejs": 2,
                //                 "helpers": true,
                //                 "regenerator": true,
                //                 "useESModules": false
                //             }
                //         ]
                //     ]
                // }
            }]
        },
        plugins: [
            new htmlWebpackPlugin({
                template: 'index.html'
            }),
            new cleanWebpackPlugin(['dist']),
            new webpack.HotModuleReplacementPlugin()
        ],
        output: {
            // filename: 'bundle.js',
            filename: '[name].js',
            publicPath: '/',
            path: path.resolve(__dirname, 'dist')
        },
    }
    
    //package.json
    {
      "name": "webpack-demo",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "build": "webpack",
        "watch": "webpack --watch",
        "start": "webpack-dev-server",
        "server": "node server.js"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "@babel/core": "^7.3.3",
        "@babel/plugin-transform-runtime": "^7.2.0",
        "@babel/preset-env": "^7.3.1",
        "@babel/preset-react": "^7.0.0",
        "autoprefixer": "^9.4.8",
        "babel-loader": "^8.0.5",
        "clean-webpack-plugin": "^1.0.1",
        "css-loader": "^2.1.0",
        "express": "^4.16.4",
        "file-loader": "^3.0.1",
        "html-webpack-plugin": "^3.2.0",
        "node-sass": "^4.11.0",
        "postcss-loader": "^3.0.0",
        "sass-loader": "^7.1.0",
        "style-loader": "^0.23.1",
        "url-loader": "^1.1.2",
        "webpack": "^4.29.5",
        "webpack-cli": "^3.2.3",
        "webpack-dev-middleware": "^3.6.0",
        "webpack-dev-server": "^3.2.0"
      },
      "dependencies": {
        "@babel/polyfill": "^7.2.5",
        "@babel/runtime": "^7.3.1",
        "@babel/runtime-corejs2": "^7.3.1",
        "react": "^16.8.2",
        "react-dom": "^16.8.2"
      }
    }
    
    //postcss.config.js
    module.exports = {
      plugins: [
        require('autoprefixer')
      ]
    }
    
    //.babelrc
    {
       "presets": [
            ["@babel/preset-env", {
                "useBuiltIns": "usage",
                "targets":{
                    "chrome":"67"
                }
            }],
            "@babel/preset-react"
        ]
    }
    

    第8章 运行环境

    8-1 页面加载 - 渲染过程

    题目
    从输入url到得到html的详细过程
    1)加载的形式
    输入url(或跳转页面)加载html(html)
    加载html中的静态资源(img media font js css api)
    2)加载的一个资源的过程
    浏览器根据DNS服务器得到的域名的IP地址
    向这个IP的机器发送http请求
    服务器收到、处理并返回http请求
    浏览器得到返回内容
    3)浏览器渲染页面的过程
    根据html生成DOM Tree
    根据css 生成CSSOM
    将DOM和CSSOM 整合形成 RenderTree
    根据RenderTree开始渲染和展示
    遇到<script>时,会执行并阻塞渲染

    window.onload 和 DOMContentLoaded的区别
    window.onload
    页面全局资源加载完成后才执行,包括图片、视频
    DOMContentLoad
    渲染完即可执行,此时图片、视频可能还没有加载完

    window.addEventListener('load',function(){
      //
    })
    
    document.addEventListener('DOMContentLoad',function(){
    //
    })
    
    8-2 性能优化

    原则
    多使用内存、缓存或者其他方法
    减少CPU计算、减少网络请求
    入手
    加载页面和静态资源
    页面渲染
    优化
    1.静态优化
    静态资源的合并压缩
    静态资源缓存
    使用cdn让资源加载更快
    使用SSR后端渲染,数据直接输出html中

    2.渲染优化
    css放在前面,js放在后面
    懒加载(图片懒加载、下拉加载更多)
    减少DOM查询,对DOM查询做缓存
    减少DOM操作,多个操作尽量合并到一起执行
    事件节流
    尽早执行操作(如DOMContentLoaded)

    8-3 安全性

    1.XSS 跨站请求攻击
    eg:
    写博客,同时偷偷插入一段<script>
    攻击代码中,获取cookie,发送自己的服务器
    发布博客,有人查看博客内容
    会把查看者的cookie发送到攻击者的服务器

    预防:
    前端替换关键字:
    < 改为 <

    改为 >
    后端替换关键字

    2.XSRF 跨站请求伪造
    你已登录一个购物网站,正在浏览商品
    该网站的付费接口:http://api.pay?id=100 但是没有任何验证
    然后你收到一封邮件,隐藏着<img src=http://api.pay?id=100 >
    你查看邮件的时候,你已经悄悄的付费购买了

    解决方案:
    增加验证流程,例如输入指纹、密码、短信验证码

    8-3 面试技巧

    1.简历
    简介明了,重点突出项目经历和解决方案
    把个人博客放在简历中,并且定期维护更新博客
    把个人的开源项目放到简历中,并维护开源项目
    简历千万不要造假,要保持能力和经历上的真实性
    2.如何看到加班?
    加班就像借钱,救急不救穷
    千万不要挑战面试官,不要反考面试官
    学会给面试官惊喜,但是不要太多
    遇到不会的问题,说出你知道的也可以
    谈谈你的缺点--- 说一下你最近在学习就可以了

    相关文章

      网友评论

          本文标题:前端JavaScript面试技巧

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