美文网首页
前端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.如何看到加班?
加班就像借钱,救急不救穷
千万不要挑战面试官,不要反考面试官
学会给面试官惊喜,但是不要太多
遇到不会的问题,说出你知道的也可以
谈谈你的缺点--- 说一下你最近在学习就可以了

相关文章

  • Front Interview导航2020-09-07

    JavaScript 【面试】前端JavaScript面试技巧【反向面试】—反问面试官的问题玩转经典十大Top10...

  • 前端JavaScript面试技巧

    导读 请搭配导图一起看 基层攻城狮 基础知识 高级攻城狮 项目经验 架构师 解决方案https://zhuanla...

  • 前端JavaScript面试技巧

    1-1 课程概述 要做什么?——讲解前端 JS 基础面试题 哪些部分?——JS 基础,JS-WEB-API,JS ...

  • 前端JavaScript面试技巧

    第5章 JS-Web-API(上) 从基础知识到JSWebAPI 下面来进行一个抛砖引玉回顾JS基础知识1.变量类...

  • 前端JavaScript面试技巧

    先看几道面试题: 1、JS中使用typeof能得到哪些类型。//JS变量类型2、何时使用“==”、“===”。//...

  • 前端JavaScript面试技巧

    加vx:dailaoer-com 9.9¥全 这是一门让你在前端面试脱颖而出的课程,BAT高级前端工程师亲授,以搞...

  • 前端随笔-面试

    阿里巴巴前端面试经历 JavaScript权威面试指南

  • 前端面试的经典题

    前端面试的经典题 前端面试三部曲 前端面试概念收集器 前端面试的经典题 前端面试的难题和怪题 Javascript...

  • 前端JavaScript高级面试技巧[1]

    第1章 课程介绍 1-1 导学 课程概述 做什么?— 讲解前端 JS 高级面试题 哪些部分?— 高级基础, 框架原...

  • 前端JavaScript高级面试技巧[2]

    第5章 虚拟 DOM vdom 是 vue 和 React 的核心 vdom 比较独立,使用也比较简单 vdom ...

网友评论

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

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