置身世外只为暗中观察!!!Hello大家好,我是魔王哪吒!
你需要一些HTML和css的基础知识,掌握JavaScript和ES6的基本语法,对事物的好奇心。
typeof运算符:
考点:JS变量类型
代码:
// 判断所有值的类型
let a; typeof a // 'undefined'
const str = 'abc'; typeof str // 'string'
const n = 10; typeof n // 'number'
const b = true; typeof b // 'boolean'
const s = Symbol('s'); typeof s // 'symbol'
// 能够判断函数
typeof console.log // 'function'
typeof function(){} // 'function'
// 能够识别引用类型
typeof null // 'object'
typeof ['a','b'] // 'object'
typeof {x:10} // 'object'
考点:强制类型转换
字符串拼接的类型转换
const a = 10 + 1 // 11
const b = 10 + '10' // '1010'
const c = true + '1' // true1
解决方法:
10 + parseInt('1') // 11
==
运算符的类型转换
100 == '100' // true
0 == '' // true
0 == false // true
false == '' // true
null == undefined // true
类型转换
0
之外的所有数字,转换为布尔型都为true
。“ ”
之外的所有字符,转换为布尔型都为true
。null
和undefined
转换为布尔型为false
。什么时候使用===
,什么时候使用==
除了
==
null外,其他地方用===
const obj = {a:1}
if(obj.b==null){}
// 相当于
//if(obj.b === null || obj.b === undefined){}
考点:页面加载过程
考点:JS作用域
考点:性能,体验优化
考点:JS异步
值类型的表示:
// 值类型
let a = 10
let b = a
a= 20
console.log(b); // 10
引用类型的表示:
// 引用类型
let a = { age:12 }
let b = a
b.age = 13
console.log(a.age) // 13
代码:
// 浅拷贝
const obj1 = {
age: 12,
name: 'web',
address: {
city: 'beijing'
},
}
const obj2 = obj1
obj2.address.city = 'shanghai'
console.log(obj1.address.city)
结果:
shanghai
深拷贝:定义要拷贝的对象
const obj2 = deepClone(obj1)
obj2.address.city = 'shanghai'
console.log(obj1.address.city)
function deepClone(obj = {}){
if(typeof obj !== 'object' || obj == null){
// obj是null,或者不是对象和数组情况,直接返回
return 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
}
深拷贝结果
beijing
a instanceof Array
jquery
,考虑插件和扩展性?代码:
class jQuery {
constructor(selector){
const result = document.querySelectorAll(selector)
const length = result.length
for(let i=0; i{
elem.addEventListener(type,fn,false)
})
}
}
插件的扩展性
jQuery.prototype.dialog = function(info) {
alert(info)
}
复写机制:
class myJQuery extends jQuery {
constructor(selector) {
super(selector)
}
// 扩展自己的方法
study(){
}
}
class
的原型本质,如何理解?constructor
代码:
// 类
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
study() {
console.log('study')
}
}
// 通过类 new 对象,实例
const web = new Person('哪吒', 10)
class实际上是函数,可见的语法糖
typeof Student
结果:
"function"
typeof People
结果:
"function"
extends
super
原型关系:
class
都有显示原型prototype
__proto__
__proto__
指向对应class
的prototype
console.log(Student.prototype.__proto__)
console.log(People.prototype)
console.log(People.prototype === Student.prototype.__proto__)
[] instanceof Array // true
[] instanceof Object // true
{} instanceof Object // true
this
的不同应用场景下,如何取值?bind
函数创建10个a标签,点击弹出对应序号
let i, a
for(i=0; i<10; i++) {
a=document.createElement('a')
a.innerHTML = i + '
'
a.addEventListener('click', function(e){
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
}
作用域分:
代码:
let a = 0
function fn1() {
let a1 = 100
function fn2() {
let a2 = 200
function fn3() {
let a3 = 300
return a+a1+a2+a3
}
fn3()
}
fn2()
}
fn1()
块级作用域
if(true) {
let x=100
}
console.log(x) // 会报错
如果一个变量在当前作用域没有定义,但被使用了,向上级作用域去找,一层一层一次寻找,直到找到为止,如果到了全局作用域都没有找到,就会报错xx is not defined
闭包的表现:
做一个简单的
cache
工具
闭包隐藏数据
function createCache() {
const data={}
// 闭包中的数据,被隐藏,不被外界访问
return {
set: function(key,val) {
data[key] = val
},
get: function(key){
return data[key]
}
}
}
const c = createCache()
c.set('a', 100)
console.log(c.get('a'))
函数作为返回值
function create(){
let a = 100
return function(){
console.log(a)
}
}
let fn = create()
let a = 200
fn()
结果:
100
函数作为参数
function print(fn) {
let a = 200
fn()
}
let a = 100
function fn(){
console.log(a)
}
print(fn)
结果:
100
所有自由变量的查找是在函数定义的地方,向上级作用域查找,不是执行的地方。
call,apply,bind
被调用class
方法中被调用this
取什么值,是在函数执行的时候确定的,不是函数定义的时候确定的。
call
指向,bind
会返回新的函数
代码:
function fn1(){
console.log(this)
}
fn1() // window
fn1.call({x:10}) // {x:10}
const fn2 = fn1.bind({x:20})
fn2() // {x:20}
代码:
const Jeskson = {
name: 'web',
sayHi() {
// this是指当前对象
console.log(this)
},
wait(){
setTimeout(function(){
// this === window
console.log(this)
}
}
}
代码:
const Jeskson = {
name: 'web',
sayHi() {
// this是指当前对象
console.log(this)
},
wait() {
setTimeout(()=>{
// this指当前对象
console.log(this)
})
}
}
代码:
class People {
constructor(name){
this.name = name
this.age = 20
}
sayHi(){
console.log(this)
}
}
const Jeskson = new People('web')
Jeskson.sayHi() // Jeskson 对象
手写bind
函数
Function.prototype.bind1 = function(){
// 将参数解析为数组
const args = Array.prototype.slice.call(arguments)
// 获取this
const t = args.shift()
const self = this // 当前函数
// 返回一个函数
return function() {
// 执行原函数,并返回结果
return self.apply(t, args)
}
}
代码:
function fn1(a,b,c) {
console.log('this',this)
console.log(a,b,c)
return 'this is fn1'
}
const fn2 = fn1.bind ({x:100},10,20,30)
const res = fn2()
console.log(res)
Chrome
:
fn1.hasOwnProperty('bind')
//false
fn1.__proto__ == Function.prototype
// true
Function.prototype.apply/call/bind
Promise
加载一张图片代码:
// setTimeout笔试题
console.log(1)
setTimeout(function(){
console.log(2)
},1000)
console.log(3)
setTimeout(function(){
console.log(4)
},0)
console.log(5)
callback hell
和Promise
JS是单线程语言,同时只能做一件事
浏览器和nodejs
支持js
启动进程,如web worker
JS和dom渲染共用同一线程。
异步:
console.log(100)
setTimeout(function(){
console.log(200)
},1000)
console.log(300)
同步
console.log(100)
alert(200)
console.log(300)
异步和同步的区别
js
是单线程语言手写用Promise
加载一张图片
function loadImg(src) {
return new Promise(
(resolve, reject) => {
const img = document.createElement('img')
img.onload = () => {
resolve(img)
}
img.onerror = () => {
const err = new Error(`图片加载失败 ${src}`)
reject(err)
}
img.src = src
}
)
}
const url = ''
loadImg(url).then(img => {
console.log(img.width)
return img
}).then(img => {
console.log(img.height)
}).catch(ex=>console.error(ex))
Promise
解决callback hell
异步,以回调callback
函数形式
第一网络请求,如ajax
图片加载,第二定时任务,如setTimeout
。
//ajax
console.log('start')
$.get('./data.json', function(data1){
console.log(data1)
})
console.log('end')
图片的加载
console.log('start')
let img = document.createElement('img')
img.onload = function() {
console.log('loaded')
}
img.src="/xxx.png"
console.log('end')
代码应用场景:
// setTimeout
console.log(100)
setTimeout(function(){
console.log(200)
},1000)
console.log(300)
// setInterval
console.log(100)
setInterval(function(){
console.log(200)
},1000)
console.log(300)
Promise
代码:
function getData(url){
return new Promise((resolve, reject) => {
$.ajax({
url,
success(data) {
resolve(data)
},
error(err) {
reject(err)
}
})
}
}
Promise
const url1 = '/data1.json'
const url2 = '/data2.json'
const url3 = '/data3.json'
getData(url1).then(data1=>{
console.log(data1)
return getData(url2)
}).then(data2 => {
console.log(data2)
return getData(url3)
}).then(data3 => {
console.log(data3)
}).catch(err => console.error(err))
calback hell
,回调地狱
代码:
// 获取第一个数据
$.get(url1, (data1) => {
console.log(data1)
// 获取第二个数据
$.get(url2, (data2) => {
console.log(data2)
// 获取第三个数据
$.get(url3, (data3) => {
console.log(data3)
// 还可能获取更多的数据
})
})
})
Dom操作,操作网页上的Dom元素,浏览器上的文本,图片
Bom操作,操作浏览器上的一些事情,浏览器的导航,地址等
事件绑定,ajax,存储
DOM,Document Object Model
DOM
的本质,节点操作,结构操作,DOM
性能
xml
是一种可扩展的标记语言,可以描述任何结构的数据,html
是一种特定的xml
。
DOM
的本质,它就是一颗树。
Dom
节点attribute
property
获取DOM
节点
const div1 = document.getElementById('div1') // 元素
const divList = document.getElementsByTagName('div') // 集合
console.log(divlist.length)
console.log(divList[0])
const containerList = document.getElementsByClassName('.container') // 集合
const pList = document.querySelectorAll('p') // 集合
DOM
节点的property
const pList = document.querySelectorAll('p');
const p = pList[0]
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)
property
和attribute
property
修改对象属性,不会体现到html
结构中
attribute
修改html
属性,会改变html
结构
两种都有可能引起DOM
重新渲染
DOM
结构操作
新增,插入节点
const div1 = document.getElementById('div1')
// 添加新节点
const p1 = document.createElement('p')
p1.innerHTML = 'this is p1'
div1.appendChild(p1)
const p2 = document.getElementById('p2')
div1.appendChild(p2)
获取子元素列表和获取父元素
//获取子元素列表
const div1 = document.getElementById('div1')
const child = div1.childNodes
//获取父元素
const div1 = document.getElementById('div1')
const parent = div1.parentNode
删除节点
const div1 = document.getElementById('div1')
const child = div1.childNodes
div1.removeChild(child[0])
DOM性能
DOM
操作会耗费cpu,避免频繁,对DOM
查询做缓存
DOM
查询做缓存
// 不缓存DOM查询结果
for(let=0; i
讲频繁的操作修改为一次性操作
const listNode = document.getElementById('list')
// 创建一个文档片段,此时没有插入到dom树中
const frag = document.createDocumentFragment();
// 执行插入
for(let x=0; x<10; x++) {
const li = document.createElement("li")
li.innerHTML="List item"+x
frag.appendChild(li)
}
// 都完成后,再插入到dom树中
listNode.appendChild(frag)
问题:
dom
是哪种数据结构dom
操作的常用api
attr
和property
的区别dom
节点,考虑性能问题property
和attribute
的区别
property
修改对象属性,不会体现到html
结构中attribute
修改html
属性,会改变html
结构两者都有可能引起dom
重新渲染
dom
本质dom
节点操作dom
结构操作dom
性能BOM
操作browser object model
问题:如何识别浏览器的类型
问题:分析拆解url
各个部分
代码:
//navigator
const ua = navigator.userAgent
const isChrome = ua.indexOf('Chrome`)
console.log(isChrome)
代码:
//screen
console.log(screen.width)
console.log(screen.height)
ajax
代码:
//get请求
const xhr = new XMLHttpRequest()
xhr.open('GET','/api', true)
xhr.onreadystatechange = function() {
// 这里的函数异步执行
if (xhr.readyState === 4){
if(xhr.state === 200) {
alert(xhr.responseText);
}
}
}
xhr.send(null)
xhr.readyState
send()
方法send()
方法,正在发送请求send()
方法执行完成,已经接收到全部响应内容xhr.status
同源策略-跨域
ajax
请求时,浏览器要求当前网页和server
必须同源
同源就是:协议,域名,端口,一致
代码
function ajax(url) {
const p = new Promise((resolve, reject)=>{
const xhr = new XMLHttpRequest()
xhr.open('GET',url,true)
xhr.onreadystatechange=function(){
if(xhr.readyState === 4){
if(xhr.status===2000) {
resolve(
JSON.parse(xhr.responseText)
)
}else if(xhr.status === 404) {
reject(new Error('404 not found'))
}
}
}
xhr.send(null)
}
}
代码:
const btn = document.getElementById('btn1')
btn.addEventListener('click',event=>{
console.log('clicked')
})
代码:
//通用的绑定函数
function bindEvent(elem, type, fn)
elem.addEventListener(type,fn)
}
const a = document.getElementById('web')
bindEvent(a, 'click', e=>{
e.preventDefault()
alert('clicked')
})
代码:
web
it
it
it
it
it
const p1 = document.getElementById('p1')
const body = document.body
bindEvent(p1, 'click', e=>{
e.stopPropagation() // 阻止冒泡
alert('web')
})
bindEvent(body, 'click', e=>{
alert('it')
})
代码:
const div1 = document.getElementById('div1')
div1.addEventListener('click', e=>{
const target = e.target
if(e.nodeName === 'A') {
alert(target.innerHTML)
}
})
事件代理,可以减少浏览器内存占用
通用的事件绑定函数
const btn1 = document.geteElementById('btn1')
bindEvent(btn1,'click',event=>{
// console.log(event.target) // 获取触发的元素
event.preventDefault() // 阻止默认行为
alert('clicked')
})
const div2 = document.getElementById('div2')
bindEvent(div2,'click',event=>{
event.preventDefault()
const target = event.target
if(target.nodeName === 'A') {
alert(target.innerHTML)
}
})
代码:
function bindEvent(elem, type, selector, fn) {
if(fn==null) {
fn = selector
selector = null
}
elem.addEventListener(type, e=>{
let target
if(selector) {
// 需要代理
target = e.target
if(target.matches(selector)){
fn.call(target, e)
}
} else {
// 不需要代理
fn(e)
}
})
}
cookie
,localStorage
,sessionStorage
区别
localStorage
数据会永远存储,除非代码回手动删除sessionStorage
数据只存在于当前会话,浏览器关闭则清空一般用localStorage
会更多一些
http
请求时需要发送到服务器端,增加请求数据量html5
专门为存储而设计的,最大可为5Mapi
简单易用setItem
,getItem
不会随着http
请求被发送出去
代码:
localStorage.setItem('a',100)
localStorage.getItem('a')
代码:
sessionStorage.setItem('a',100)
sessionStorage.getItem('a')
代码:常用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 xx
git merge xxx
chrome调试工具
Elements
Network
Console
Application
debugger
移动端h5页,查看网络请求,需要用工具抓包
windows
一般用fiddler
代码:
const path = require('path')
module.exports = {
mode: 'development',
entry: path.join(__dirname, 'src', 'index.js'),
output: {
filename: 'bundle.js',
path: path.join(__dirname,'dist')
}
}
线上机器一般都是linux
代码:
ssh work
ls
rm -rf abc
cd dist
mv index.html index1.html
rm a1.js
touch d.js
rm -rf d.js
server
端有nodejs
url
到渲染出页面的整个过程资源的形式:html
代码,媒体文件,如图片,视频等,javascript
,css
。
加载过程:dns
解析,域名,ip
地址。浏览器根据ip
地址向服务器发起http
请求。
服务器处理http
请求,并返回给浏览器。
渲染过程,根据html
代码生成dom tree
,根据css
代码生成cssom
。讲dom tree
和cssom
整合行程render tree
。
根据render tree
渲染页面,遇到script
暂停渲染,优先加载并执行js
代码,完成再继续。
window.onLoad
和DOMContentLoaded
代码:
window.addEventListener('load',function(){
// 页面的全部资源加载完才会执行,包括图片,视频等
})
document.addEventListener('DOMContentLoad',function(){
// dom渲染完既可执行,此时图片,视频还可能没有加载完
})
window.onload
资源全部加载完才能执行,包括图片DOMContentLoaded DOM
渲染完成即可,图片可能还没下载手写防抖,节流
原则:
让加载更快,渲染更快,减少资源体积。减少访问次数,合并代码,ssr
服务器端渲染,缓存。
对dom
查询进行缓存,频繁dom
操作,合并到一起插入dom
结构,节流throttle
防抖debounce
。
ssr
服务器端渲染,讲网页和数据一起加载,一起渲染
非ssr,先加载网页,再加载数据,再渲染数据
代码:
防抖,用户输入结束或暂停时,才会触发change事件。
代码:
const input1 = document.getElementById('input1')
input1.addEventListener('keyup', function(){
console.log(input1.value)
}}
代码:
const input1 = document.getElementById('input1')
let timer = null
input1.addEventListener('keyup', function(){
if(timer){
clearTimeout(timer)
}
timer = setTimeout(()=>{
// 模拟触发change事件
console.log(input1.value)
// 清空定时器
timer = null
},500)
})
debounce防抖代码:
function debounce(fn, delay = 500) {
// timer 是闭包中的
let timer = null
return function() {
if(timer) {
clearTimeout(timer)
}
timer = setTimeout(()=>{
fn.apply(this, arguments)
timer = null
},delay)
}
}
input1.addEventListener('keyup', debounce(()=>{
console.log(input1.value)
}),600)
节流throttle
拖拽一个元素时,要随时拿到该元素被拖拽的位置
代码:
const div1 = document.getElementById('div1')
let timer = null
div1.addEventListener('drag',function(e){
if(timer){
return
}
timer = setTimeout(()=>{
console.log(e.offsetX, e.offsetY)
timer = null
},100)
})
节流代码:
function throttle(fn, delay = 100) {
let timer = null
return function() {
if(timer) {
return
}
timer = setTimeout(()=>{
fn.applay(this,arguments)
timer = null
},delay)
}
}
div1.addEventListener('drag',throttle(function(e){
console.log(e.offsetX,e.offsetY)
},200))
前端web常见的攻击方式有哪些?
xss跨站请求攻击
xsrf跨站请求伪造
var是es5的语法,let const 是es6语法,var有变量提升
var和Let是变量,const是常量,不可修改
let const有块级作用域,var没有
object和function
强制类型转换和隐式类型转换
强制:parseInt,parseFloat,toString等
lodash.isEqual
//实现如下效果
const obj1 = {a:10, b:{x:100,y:200}}
const obj2 = {a:10, b:{x:100,y:200}}
isEqual(objq,obj2) === true
判断是否是对象或数组
代码:
function isObject(obj){
return typeof ojb === 'object' && obj !== null
}
// 全相等
function isEqual(obj1,obj2){
if(!isObject(obj1) || !isObject(obj2)) {
// 值类型
return obj1===obj2
}
if(obj1===obj2){
return true
}
// 两个都是对象或数组,而且不相等
const obj1key = Object.keys(obj1)
const obj2key = Object.keys(obj2)
if(obj1key.length !== obj2key.length){
return false
}
for(let key in obj1){
const res = isEqual(obj1[key],obj2[key])
if(!res){
return false
}
}
return true
}
split()和join()的区别
'1-2-3'.split('-') // [1,2,3]
[1,2,3].join('-') // '1-2-3'
数组的pop,push,unshift,shift
功能分别是什么,返回值是什么,有什么影响。
pop返回删除的最后一个值
push返回追加后元素的长度
unshift插入到最前面,返回长度length
shift删除最前面的,返回删除的值
代码:
fn.call(this, p1,p2,p3)
fn.apply(this, argument)
代码:
const p1 = document.getElementById('p1')
const body = document.body
bindEvent(p1, 'click', e=>{
e.stopProgation();
alert()
})
bindEvent(body, 'click', e=>{
alert()
})
自由变量的查找,要在函数定义的地方,不是执行的地方
闭包不要乱用,变量会常驻内容,不会释放
闭包:
function create() {
let a=100
return function(){
console.log(a)
}
}
let fn = create()
let a=200
fn() // 100
event.stopPropagation()
event.preventDefault()
代码:
// 新建节点
const newP = document.createElement('p')
newP.innerHTML = 'this is newP'
// 插入节点
div1.appendChild(newP)
// 移动节点
const p1 = document.getElementById('p1')
div2.appendChild(p1)
//获取父元素
console.log(p1.parentNode)
代码:
const list = document.getElementById('list')
const frag = document.createDocumentFragment()
for(let i=0; i<20; i++){
const li = document.createElement('li')
li.innerHTML = 'list'
frag.appendChild(li)
}
list.appendChild(frag)
jsonp的原理,为什么它不是真正的ajax
浏览器的同源策略和跨域
load:
页面的区别资源加载完才会执行
ready:
dom渲染完既可执行,图片,视频等还没有加载完
函数声明
function fn(){...}
函数表达式:
const fn = function(){...}
函数声明会预加载,而函数表达式不会
{}
等同new Object()
,原型Object.prototype代码:
let i
for (i = 1; i <= 3; i++) {
setTimeout(function(){
console.log(i)
},0)
}
代码:
let a = 100
function test() {
alert(a)
a = 10
alert(a)
}
test()
alert(a)
手写字符串trim方法,保证浏览器兼容性
用Js实现继承
代码:
try {
// todo
}catch(error) {
console.error(error)
}finally{
}
json是一种数据格式,本质是一段字符串,json格式和js对象结构一致。
window.JSON
是一个全局对象,JSON。stringify
,JSON.parse
获取当前页面url参数
传统方式,查找location.search
新api,URLSearchParams
代码:
// 1
function queryToObj(){
const res={}
const search = location.search.substr(1)
search.split('&').forEach(res => {
const arr = res.split('=')
const key = arr[0]
const key = arr[1]
res[key] = val
})
}
使用URLSearchParams
function queryToObj() {
const res = {}
const pList = new URLSearchParams(location.search)
pList.forEach((val,key) => {
res[key] = val
})
return res
}
手写数组flatern
代码:
function flat(arr) {
const isDeep = arr.some(item=> item instanceof Array)
if(!isDeep) {
return arr
}
const res = Array.prototype.concat.apply([],arr)
return flat(res)
}
数组去重
代码:
function unique(arr) {
const res=[]
arr.forEach(item => {
if(res.indexOf(item) < 0) {
res.push(item)
}
})
return res
}
使用Set
function unique(arr) {
const set = new Set(arr)
return [...set]
}
RAF requestAnimateFrame
代码:
function deepClone(obj = {}) {
if(type of obj !== 'object' || obj == null){
return obj
}
let result
if(obj instanceof Array) {
result = []
}else{
result = {}
}
for(let key in obj){
if(obj.hasOwnProperty(key)){
result[key] = deepClone(obj[key])
}
}
return result
}
Object.assign
不是深拷贝!
原则:多使用内存,缓存,减少计算,网络请求
加载页面,页面渲染,页面操作等多多思考问题。