介绍JS的基本数据类型
Number
String
Boolean
null
undefined
object
symbol
bigInt
其中object包括
array
function
Date
console.log(1+true) //2
console.log('name'+true) //nametrue
console.log(undefined + 1) //NaN
console.log([] == []) //false
console.log(null == undefined) //true
console.log(null === undefined) // false
console.log(!0) //true
console.log(!'0') //false
typeof的返回数据类型
symbol
number
string
undefined
boolean
function
object
console.log(typeof null) //object
console.log(typeof undefined) //undefined
console.log(typeof array) //object
JavaScript有几种数据类型
基本数据类型和复杂数据类型
在栈中存放基本数据类型
在堆中存储复杂数据类型(在栈中存放地址,地址指向堆中的数据)
什么是栈,什么是堆
1.在数据结构中,栈可以看作成一个桶,按照先进后出的方式存储数据;堆可以当作成一棵树,按照优先级存储数据,优先级高的数据先存储。
2.在操作系统中,栈自动自动分配相对固定大小的内存空间,由系统分配释放。而堆动态分配内存,内存大小不一,由程序员分配释放。
undefined和null的区别
1.undefined表示未定义的变量
2.null表示空对象
undefined == null //true
nudefined === null //false
怎么判断数据类型
1.typeof
2.instanceof
3.object.prototype.tostring.call()
4.constructor
检测数组的四种方法
1.instanceof
2.Array.isArray()
3.constructor
4.object.prototype.tostring.call()
instanceof的作用
instanceof用于判断构造函数的prototype属性是否出现在对象的原型链上
箭头函数和普通函数的区别
1.首先是外形上的不同
2.箭头函数都是匿名函数
3.箭头函数不能用于构造函数,不能使用new
4.箭头函数不会创建自己的this,箭头函数里的this永远指向其上下文,而普通函数里的this指向调用它的那个对象
5.箭头函数不能使用call、apply、bind改变this指向,不能使用argument。
匿名函数
在函数表达式中,创建一个函数并将它赋值给一个变量,若此时function关键字后咩有标识符,那么创建的函数可称为匿名函数。
匿名函数的this指向
// this对象是在运行时基于函数执行环境绑定的,在全局函数中,this=window,在函数被作为某个对象的方法调用的时候,this等于这个对象。
// 匿名函数的执行环境具有全局性,所以它的this一般指向window
var name = 'window'
var person = {
name: 'dd',
sayName: function(){ //这是一个匿名函数,将匿名函数赋给一个变量
return function(){
return this.name
}
}
}
console.log(person.sayName()()) // window
解决办法1,把外部作用域的this传递给匿名函数
var name = 'window'
var person = {
name: 'dd'
sayName: function(){
var that = this
return function(){
return that.name
}
}
}
console.log(person.sayName()()) // dd
解决办法2,使用call、apply、bind改变函数内部的this指向
person.sayName().call(person)
person.sayName().apply(person)
person.sayName().bind(person)
isNaN()
// NaN意为不是一个数字,isNaN()方法判断非数字,是数字返回false
如何将字符串转换为数字
1.parseInt()
2.parseFloat()
3.Number()强制转换
4.+-*/隐式转换
如何将数字转换为字符串
1.toString() num.toString()
2.String() String(num)
3.加号拼接字符串
如何将字符串转换为数组
1.str.split('')
如何将数组转换为字符串
1.arr.join('')
2.arr.toString()
将伪数组转换为数组
1.Array.from(arr)
2.使用扩展运算符[...arr]
let arr = new Set([1,2,3,4,3,2])
console.log(Array.from(arr))
consloe.log([...arr])
数组方法
arr.push() 原数组改变(后面新增)
arr.pop() 原数组改变(后面删除一个)
arr.unshift() 原数组改变(前面新增)
arr.shift() 原数组改变(前面删除一个)
arr.reverse() 原数组改变
arr.sort() 原数组改变
arr.concat() 原数组不变
arr.splice(index,num) 原数组改变
arr.slice(start,end) 原数组不变
arr.forEach(function((item,index) => {} )) //遍历数组,原数组不变
arr.filter(function((item,index) => {} )) //过滤数组,原数组不变
arr.map(function((item,index) => {} )) //映射数组,原数组不变
arr.some(function((item,index) => {} )) //数组中是否有某个值满足某一条件,原数组不变
arr.every(function((item,index) => {} )) //数组中的值是否都满足某一条件,原数组不变
arr.includes() //判断数组中是否包含给定的值,原数组不变
arr.indexOf() //查找某个元素的索引值(返回第一个满足条件的索引值,没有则返回-1),原数组不变
Set数据结构
1.类似于数组,但是成员的值都是唯一的,没有重复的值,是一个构造函数(可以利用set做数组去重 var arr =new Set([1,1,2,3,4])) console.log(Array.from(arr))
2.向set中添加成员时,不会发生类型转换( 5 和 "5"是不相等的)
3.向set中添加的对象总是不相等的
let mySet = new Set()
mySet.size //set属性,有多长
mySet.add(5) //添加成员,返回set本身
mySet.delete(5) //删除某个值,返回布尔值
mySet.has(5) // 是否存在某个值,返回布尔值
mySet.clear() // 清楚set成员
meSet.keys() //返回键名
mySet.values() //返回键值
let mySet = new Set()
mySet.add(5)不等同于mySet.add("5")
mySet.add({})不等同于mySet.add({})
Map数据结构
类似于set,以键值对的形式存储数据,是有序的。键名可以是任意类型
1.map和object的区别
1.object是无序的,而map是有序的
2.object的key必须是简单数据类型,map的key可以是JavaScript支持的所有数据类型
3.map访问数据是通过myMap.get(),object通过obj.或者obj[]访问数据。
const myMap = new Map()
myMap.size // map属性,有多长
myMap.set(key,value) //设置属性,更新或者添加
myMap.get(key) //读取对应key的键值
myMap.has(key) //是否存在某个键,返回布尔值
myMap.delete(key) //删除某个key
myMap.clear() //清楚所有成员
myMap.keys() //返回键名
myMap.values() //返回键值
super关键字
super关键字用于访问和调用父类上的函数
JavaScript创建对象的几种方式
1.使用字面量创建对象(let obj = {})
2.使用new Object创建对象(var obj = new Object() obl.name)
3.使用构造函数创建对象
function Star(name.age){
this.name = name
this.age = age
}
var dd = new Star('dd',21)
call()和apple()的区别
1.call()和apple()都可以调用函数,都可以改变函数内部的this指向
2.call()传递参数arg1、arg2,而apple()必须以数组的形式传递参数
object.defineproperty()
定义对象的新属性或修改原有属性
JavaScript的作用域链
当内部函数访问外部函数变量的时候,采取的是链式查找的方式来决定取那个值,这个结构我们称为作用域链。
什么是DOM和BOM
1.DOM指的是文档对象模型,把文档当作一个对象,主要定义了处理网页内容的方法和接口。
2.BOM指的是浏览器对象模型,把浏览器当作一个对象,主要定义了与浏览器进行交互的方法和接口。
DOM
1.创建节点(var li = document.createElement(li))
2.添加节点(ul.appendChild(li))
3.插入节点(ul.insertBefore(li,ul,children[0]))
4.移除节点(ul.removeChild(ul.children[0]))
5.复制节点(node.cloneNode())
6.查找节点(document.getElementById()、 document.getElementByClassName()、
document.getElementByTagName()、document.querySelector())
1.添加节点以及属性
var ul = document.createElement('ul')
ul.setAttribute('id','box')
var li = document.createElement('li')
li.innerHTML = '我是li'
ul.appendChild('li')
DOM操作元素
1.改变元素内容
div.innerHTML = '2022/2/25'
2.修改元素属性
img.src = 'images/dd.jpg'
3.修改表单属性
input.value = '我变了'
4.修改样式属性(易忘)
div.style.width = '250px'
dic.style.backgroundColor = 'red'
事件是什么
事件是用户操作页面时发生的交互动作
ul.onclick = function(e){}
ul.addEventListner('click',function(e){},false)
false表示事件冒泡
true表示事件捕获
默认值是false
事件流的三个阶段
1.捕获阶段
2.处于目标阶段
3.冒泡阶段
阻止事件冒泡
1. e.stopPropagation()
2. e.cancelBubble = false
事件委托是什么
事件委托就是利用事件冒泡原理,把事件添加到父级上,由父级统一处理多个子元素的事件
ul.addEventListener('click',funtion(e){
if(e.target.nodeName == 'li'){
e.target.style.background = 'red'
}
},false)
鼠标事件对象
1.鼠标在可视区的x和y坐标
e.clientX
e.clientY
2.鼠标在页面文档的x和y坐标
e.pageX
e.pageY
通常使用场景
img{
position: absolute
}
img.style.left = e.pageX
img.style.top = e.pageY
BOM
1.setTimeout定时器
setTimeout(回调函数, [延迟毫秒数])
2.setInterval定时器
setInterval(回调函数, [延迟的毫秒数])
3.清除定时器
1.clearTimeout(定时器名)
2.clearInterval(定时器名)
location对象
1.关闭当前页,打开URL页面
window.location.herf = 'url'
2.保留当前页,打开新窗口
window.open(url)
history对象
1.前进功能
history.forward()
2.后退功能
history.back()
3.前进后退功能
history.go(1)
history.go(-1)
JS作用域
1.全局作用域
2.局部作用域
3.块级作用域
var name = 'dd' //全局变量
function fn(){
var age = 18 //局部作用域
sex = '男' //全局作用域
console.log(name)
}
作用域链
内部函数访问外部函数的变量,采取的链式查找的方式一层一层向上查找,就称为作用域链
作用域链的原则: 就近原则
*什么是闭包(重点)
闭包是指有权访问另一个函数作用域变量的函数
闭包的实现
就是在函数内部再定义一个函数(每次外部函数执行的时候,就会开辟一个新的空间)
理解
闭包就是一个函数以及这个函数能够访问到的变量的总和
比如说
function fn(){
var name = 'dd'
function fn2(){
console.log(name)
}
return fn2()
}
var dd = fn()
dd()
// 当dd执行的时候,想要访问name,如果没有return fn2的话,是无法访问的
// 然而现在return fn2之后,外部函数就能够访问函数内部的函数了。
// 那么正常使用的过程中,肯定不只是单纯的获取这个值,而是想要对name做一些变化,这时fn2的 目的就是给name做一些操作。
比如说
function fn(){
var name = 'dd'
funtion fn2(){
console.log(name+'love')
}
}
var dd = fn()
dd()
闭包的用途
1.闭包能够读取其他函数内部的变量
2.让这些变量的值始终保持在内存中(会造成内存泄露)
闭包常见的使用场景:setTimeout的第一个函数不能携带参数,利用闭包可以携带参数
哪些操作会造成内存泄漏
1.意外的全局变量
2.闭包
3.被遗忘的定时器和回调函数
严格模式
1.变量名必须先声明再使用
2.禁止使用with语句
3.禁止this关键字指向全局变量
4.对象的属性不能重名
new运算符具体干了什么
1.首先创建一个空对象
2.this指向这个空对象
3.执行构造函数,给空对象添加属性和方法
4.返回这个对象
对于JSON的了解
Json是一种数据交换格式,作为前后端数据交换的方式。
我们能够把任何JavaScript对象转换为JSON,然后将JSON发送到服务器
我们也能把从服务器接收到的任何JSON转换为JavaScript对象
Ajax是什么
Ajax指的是通过JavaScript的异步通信,从服务器获取数据,然后更新当前页面的对应部分,而不用刷新整个页面。
如何创建一个Ajax
1.创建一个异步调用对象(就是XML HTTPRuest对象)
2.创建一个新的HTTP请求(并指定该HTTP请求的方法,url及验证信息)
3.发送HTTP请求
4.设置响应HTTP请求状态变化的函数
5.获取异步调用返回的数据
6.使用JavaScript和DOM进行局部刷新
var xhr = new XMLHTTPRequest()
xhr.open('get','url')
xhr.send('id=123') //请求数据
xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status == 200){
console.log('数据返回成功')
}
}
readyState
0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成
status
200: OK
404: 找不到资源
如果是post请求的话,还需要添加
xhr.setRuquestHeader("Content-type","application/x-www-form-urlencoded")
面向过程和面向对象的区别
面向过程就是以事件为中心,一个步骤一个步骤的去完成
面向对象就是以对象为中心,我们把要完成的功能封装成一个一个的对象,调用对象的属性或方法来完成功能。
普通函数和回调函数的区别
普通函数按顺序直接调用,回调函数需要等待时间,时间到了才会去调用这个函数。
同步和异步的区别
同步就是前一个任务做完之后才能执行后一个任务。
异步就是在做这个任务的同时,还可以去做其他任务。
*事件循环(重点)
主线程里面的同步任务执行完之后,就回去到任务队列里面有没有异步任务,如果有得话就取到执行栈执行,然后再不断获取任务,执行任务,再获取,在执行,这样的机制就叫做事件循环机制。
宏任务和微任务
任务队列里面的任务可以分为宏任务和微任务。微任务是跟屁虫,一直跟在宏任务后面,一个宏任务后面可以有很多微任务。
1.宏任务
script整体代码
setTimeout()和setInterval()
setImmediate
I/O
2.微任务
promise
node中的process
object.observe
JS异步加载的方式有哪些
1.让JS最后执行
2.ansync属性(并行加载并执行,谁先加载完成谁先执行)
3.defer属性(并行加载,等HTML解析完再执行,按照顺序执行)
4.使用定时器延迟的方法
5.load事件
什么是同源
1.如果两个页面的协议、域名、端口都相同,那么这两个页面具有相同的源。
什么是同源策略
// 同源策略指的是A网站的JavaScript不允许和非同源的B网站之间进行资源交互
1.无法获取非同源网站的cookie、localStorage和indexDB
2.无法接触非同源网站的DOM
3.无法向非同源网站发送Ajax请求
*什么是跨域(重点)
// 如果两个页面的协议、域名、端口有一个不相同的话,但是其中一个页面想要访问另一个非同源网站的资源的时候,就会出现跨域的问题。(当一个请求url的协议、域名、端口三者之间任意一个与当前页面的url不同即为跨域。)
如何解决跨域问题
1.通过JsonP解决跨域
2.跨域资源共享CORS
3.WebSocket协议跨域
4.nginx代理跨域
1.JSONP解决跨域
JSONP解决跨域就是利用浏览器的script标签不受同源策略的影响,我们动态创建一个script标签,然后向服务器请求JSON数据,服务器收到请求之后,将数据放在一个我们指定的回调函数的参数的位置传回来。(JSONP只支持GET请求而不支持POST等其他类型的请求。)
2.nginx代理跨域
1.安装nginx
2.在nginx.conf文件里面修改
server{
listen 80;
server_name 192.168.1.100
location /{
proxy_pass http://192.168.1.100:8080
}
location /api{
proxy_pass http://ni.hao.sao/api
}
}
listen: 端口号的配置
server_name: 接入地址的监听
location: 拦截跳转(上面的如果路径是/或者/api结尾,就转换为proxy_pass的路径)
节流和防抖
1.节流
节流可以减少一段时间内事件的触发频率,限制一个函数在一定时间内只能触发一次。(鼠标不停点击触发,只触发一次)
2.防抖
防抖在时间被触发n秒后执行回调,如果在这n秒内事件又被触发,则重新计时(用户在不断输入值时,不随着更新,n秒后才更新)
双等号和三等号的区别
双等号会在比较的时候进行类型转换,而三等号在比较的时候不会进行隐式类型转换
浅拷贝和深拷贝
1.浅拷贝只是拷贝一层,更深层次的对象级别的只拷贝引用
2.深拷贝拷贝多层,每一级别的数据都会拷贝
浅拷贝就是拷贝基本数据类型变量和复杂数据类型的地址,深拷贝就是拷贝基本数据变量和复杂数据类型实例化
1.浅拷贝语法糖object.assign()
2.浅拷贝直接赋值
3.浅拷贝用for...in
2.深拷贝利用递归的方式实现。
3.利用Json.parse(Json.stringify())实现深拷贝。(无法转换function和undefined)
function deepopy(newobj, oldobj){
for(var k in oldobj){
var item = oldobj[k]
if(item instanceOf Array){
newobj[k] = []
deepcopy(newobj[k],item)
}else if(item instanceof Object){
newobj[k] = {}
deepcopy(newobj[k], item)
}else{
newobj[k] = item
}
}
return newpbj
}
异步编程的实现方法
1.回调函数
2.promise
3.async/await
4.Ajax
什么是promise对象
1.promise是异步编程的一种解决方案。
2.promise对象用来封装一个异步操作,并且可以获得成功或者失败的返回值。
3.promise是一个构造函数,接收一个函数作为参数,这个函数中的代码会立即执行,所以Ajax请求等异步操作可以放在这里,然后通过resolve函数将promise推向已完成状态,通过reject将promise推向已拒绝状态。resolve和reject都可以传递最多一个参数。resolve()的话就调用.then(),reject()的话就调用.catch()。
常见的异步操作:
1. 定时器
2. 接口调用
promise的三种状态
// 未决定 完成 拒绝
1.pending
2.fulfilled
3.rejected
手写一个promise
let myPromise = new Promise((resolve,reject) => {
$ajax({
url: '/api/getUserInfo',
success: function(res){
resolve(resp)
},
error: function(err){
reject(err)
}
})
})
myPromise.then((res) => {
console.log(res)
}, (err) => {
console.log(err)
})
JS动画原理
1.先获取元素的当前位置(offset获取)
2.在当前位置的基础上添加位移(eg: offset+1+'px')
3.利用定时器不断重复这个动作
4.结束定时器
(注: 元素想要位移,必须先加定位)
缓动动画的实现
使得每次添加的位移不断减小或者增大
*什么是原型(重点)
每个构造函数都有一个prototype属性,指向一个对象,这个对象就是原型对象。我们可以把那些不变的属性和方法,直接定义在prototype对象上,这样所有的对象实例就可以共享这些属性和方法了。在构造函数中,实例对象有一个proto属性,指向构造函数的prototype原型对象。每个原型都有一个constructor属性,指向该关联的构造函数。
*什么是原型链(重点)
当我们想要访问一个对象的属性的时候,如果这个对象的内部找不到这个属性,那么就去它的原型对象找,这个原型对象又有原型,这样一直往上找,直到null还没有找到,就返回undefined。
*JS继承(重点)
1.原型链继承(子类构造函数的原型等于父类构造函数的实例)(Son.protptype = new Father())(继承方法)
2.借用构造函数继承(用.call()和.apple()在子类构造函数中引用父类构造函数)(Father.call(this, 'dd'))(继承属性)
3.组合继承(组合原型链继承和借用构造函数继承)(继承属性和方法)
1.原型链继承(继承父类的属性和方法,原型中包含的引用值会在所有实例间共享)
// 父类构造函数
function Father() {
this.colors = ['red', 'blue', 'yellow'];
}
// 子类构造函数
function Son() {
}
// 继承(子类构造函数的原型等于父类构造函数的实例)
Son.prototype = new Father();(原型中包含的引用值会在所有实例间共享)
let dd = new Son();
dd.colors.push('green');
console.log(dd.colors); // ['red', 'blue', 'yellow', 'green']
let dddd = new Son();
console.log(ddd.colors); // ['red', 'blue', 'yellow', 'green']
2.借用构造函数继承(只能继承父类的实例属性和方法,不能继承原型属性和方法)
// 父类构造函数
function Father(name) {
this.colors = ['red', 'blue', 'yellow'];
this.name = name;
}
Father.prototype.getName() {
return this.name
}
// 子类构造函数
function Son() {
// 继承父类并传参
Fathet.call(this,'dengding');
this.age = 18;
}
let dd = new Son();
dd.colors.push('green');
console.log(dd.colors); // ['red', ' blue', 'yellow', 'green'];
console.log(dd.name); // dengding
console.log(dd.age); // 18
console.log(dd.getName()); // 报错(不能继承父类原型属性和方法)
let ddd = new Son();
console.log(ddd.colors); // ['red', 'blue', 'yellow']
3.组合继承(继承属性,继承方法)
// 父类构造函数
function Father(name) {
this.name = name;
this.colors = ['red', 'blue', 'yellow'];
}
Father.prototype.sayName = function() {
console.log(this.name)
}
// 子类构造函数
function Son(name,age) {
// 继承属性
Father.call(this, name);
this.age = age;
}
// 继承方法
Son.prototype = new Father();
Son.protype.sayAge = function() {
console.log(this.age);
}
let dd = new Son('dengding', 22);
dd.push.colors('green');
console.log(dd.colors); // ['red', 'blue', 'yellow', 'green']
console.log(dd.sayName); // dengding
console.log(dd.sayAge); // 22
let ddd = new Son('ddd', '18');
console.log(ddd.colors); // ['red','blue', 'yellow']
console.log(ddd.sayName); // 'ddd'
console.log(ddd.sayAge); // 18
class 类
https://blog.csdn.net/bjsyc123456/article/details/121497219?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-121497219-blog-123442559.pc_relevant_multi_platform_featuressortv2dupreplace&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-121497219-blog-123442559.pc_relevant_multi_platform_featuressortv2dupreplace&utm_relevant_index=1
https://blog.csdn.net/m0_64442921/article/details/123442559?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-123442559-blog-121497219.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-123442559-blog-121497219.pc_relevant_aa&utm_relevant_index=3
1.创建类
// 创建类 class 类名{ 实例属性 实例方法}
class Person {
name = '小明'
eat() {
console.log('在吃饭');
}
}
// 实例化一个对象
let dd = new Person();
// 调用实例对象的属性
console.log(dd.name); // 小明
// 调用实例方法
dd.eat(); // 在吃饭
2.类中的构造函数
(1) constructor是类中固定的方法名
(2) 实例化时立即执行
(3) 接受实例化时传入的参数
(4) 不是类中必须要存在的方法
class Person {
// 构造函数 接受实例化对象时传入的参数
constructor(name, age) {
this.name = name;
this.age = age;
}
// 实例方法
eat() {
console.log(`${this.name}在吃东西`);
}
}
// 实例化对象
let dd = new Person('dengding', 22);
let ddd = new Person('ddd',18);
dd.eat(); // dengding在吃东西
ddd.eat(); // ddd在吃东西
3.类的继承
类的继承子类可以使用父类的实例属性和实例方法。
如果子类有构造函数,要先使用super()方法调用父类的构造函数,否则会报语法错误
实例方法属于公开的方法,它不属于任何一个实例对象,但是所有的实例对象都可以调用。
实例对象调用方法的时候优先调用实例自身的方法,如果实例本身没有该方法,才会去调用公告方法。
// 创建父类
class Father {
// 父类构造函数
constructor(name, age) {
this.name = name;
this.age = age;
}
// 实例属性
eyes = 2;
arms = 2;
// 实例方法
eat() {
console.log(`${this.name}在吃饭`);
}
}
// 创建子类继承父类
class Son extends Father {
// 子类构造函数
constructor(name, age, addr) {
// 子类继承父类,使用super调用父类的构造函数
super(name, age);
// 子类需要多传的参数
this.addr = addr;
}
// 子类的实例属性
zheye = '程序员';
}
// 创建子类的实例化对象
let dd = new Son('dengding', 22, '广东')
console.log(dd.name); // dengding
console.log(dd.age); // 22
console.log(dd.addr); // 广东
dd.eat(); // dengding在吃饭
*说一下浏览器缓存(重点)
浏览器缓存就是把一个已经请求过的web资源(如html页面、图片、JS、数据)拷贝一份放在浏览器中。浏览器会根据进来的请求保存输入内容的副本。当下一个请求到来的时候,如果是相同的URL,浏览器会根据缓存机制决定是直接使用副本响应访问请求还是向源服务器再次发起请求。
浏览器缓存分为强缓存和协商缓存,根据响应的header内容来决定,强缓存就是不用请求服务器直接从客户端缓存中获取资源。协商缓存需要请求服务器,由服务器判定是否从缓存中获取资源。
1.强缓存的相关字段有expires,cache-control,如果expires和cache-control同时存在,cache-control的优先级更高
2.协商缓存的相关字段有Last-Modified/if-modified-Since、Etag/IF-None-Math
使用浏览器缓存的原因
1.减少网络延迟
2.降低服务器压力
3.减少网络宽带消耗
CommonJS和ES6的Module
1.CommonJS的导出是module.exports、export,导入是require
module.exports = { age: 18, name:'dd' }
2.ES6的导出是export default、export,导入是import
CommonJS输出的是一个值的拷贝,ES6模块输出的是值的引用
CommonJS是单个值导出,ES6的模块机制可以导出多个
XSS和CSRF
1.XSS
1.XSS跨站脚本攻击
2.XSS攻击的核心原理是: 不需要做任何的登录注册,它会通过合法的操作(比如在URL中输入、在评论框中输入),向你的页面注入脚本(可能是js、html代码等)
3.XSS的攻击方式: 反射性、存储型
4.XSS的防范措施主要有三个: 编码+过滤
5.编码指的是对用户输入的数据进行编码
6.过滤指的是移除用户输入的和事件相关的属性
2.CSRF
1.CSRF跨站伪造请求。
2.CSRF的防范措施主要是: token验证和隐藏令牌
观察者和发布订阅者
1.观察者模式
观察者模式就是观察者直接与目标进行交互。
观察者(触发事件) ——> 目标 目标(订阅目标) --> 观察者
2.发布订阅者模式
发布订阅者模式就是有一个事件调度中心,当数据发生变化的时候,发布消息给订阅者,然后触发相应的监听回调。订阅者和发布者互不干扰。
发布者(发布消息) --> 调度中心(触发事件) --> 订阅者 订阅者(订阅) --> 调度中心
<script> 与 <script async> <script defer> 的区别
script会按照顺序执行,但是会阻塞后面的dom渲染。
<script async>并行加载和执行,谁先加载完成谁先执行
<script defer>并行加载,等html执行完之后才执行,按照顺序执行
前端性能优化
1.请求资源优化
合并文件、压缩文件
使用雪碧图/精灵图
2.渲染优化
图片懒加载
减少DOM操作(操作dom可能会引起页面的重绘和回流)
事件委托
节流和防抖
异步加载JS
3.浏览器缓存
浏览器缓存就是把已经请求过的web资源拷贝一份放在浏览器
浏览器缓存分为强缓存和协商缓存
强缓存就是不需要请求服务器,直接从缓存中获取资源。相关字段有expire和cache-control,expire是绝对时间,cache-contro是相对时间,cache-control的优先级更高。
协商缓存就是需要请求服务器,由服务器判定是否从缓存中获取资源。相关字段有last-Modified/if-modified-Since、Etag/if-none-match
浏览器兼容问题
1.不同浏览器的内外补丁不同
*{
margin: 0;
padding: 0;
}
2.不同浏览器的li浮动的时候会有间隙
3.图片之间存在间隙
轮播图的实现
1.html部分
<div class='box'>
<ul>
<li><a><img src='imgs1.jpg'/></a></li>
<li><a><img src='imgs2.jpg'/></a></li>
<li><a><img src='imgs3.jpg'/></a></li>
<li><a><img src='imgs4.jpg'/></a></li>
<li><a><img src='imgs1.jpg'/></a></li>
</ul>
<ul id="cirs"><ul>
</div>
<div id="btn">
<span> < </span>
<span> > </span>
</div>
2.CSS部分
.box{
position: relative
width: 500px;
height: 400px;
overflow: hidden;
}
ul{
position: absolute;
top: 0;
left: 0;
width: 2500px;
height: 400px;
}
li{
float: left;
width: 500px;
height: 400px;
}
img{
width: 500px;
height: 400px
}
3.JS部分
var box = document.getElementByClassName('box')
var ul = document.getElementByTagName('ul')
var cirs = document.getElementById('cirs')
var buttons = document.getElementById('btns')
var clis = cir.children
var len = ul.children.length; // 图片张数
var width = ul.offetWidth; // 每张图片的宽度
var rates = 15; // 一张图片切换的速度
var times = 1; //切换速度的倍速
var gap = 2000; //自动切换间隙,单位为毫秒
var timer = null; // 初始化一个定时器
var picN = 0; // 当前显示的图片下标
var cirN = 0; // 当前显示图片的小圆点下标
ul.style.left = -120px + 'px' // 这一行代码是实现轮播图的重点
console.log(ul.offsetLeft) // -120
ul.style.left = ul.offsetLeft + speed + 'px' // 由上面代码衍生出这行代码
2.添加小圆点
for(var i=0;i<len;i++){
var a_li = document.createElement('li')
a_li.setArribute('calss','quiet')
cirs.appendChildren('a_li')
}
3.无缝滚动
offset获取元素的偏移量
offsetTop: 返回元素相对带有定位父元素上方的偏移量
offsetLeft: 返回元素相对带有定位父元素左方的偏移量
通过控制ul的left来控制显示哪张图片,为了实现滚动的效果,我们采用逐渐改变ul的left的值来实现。所以我们需要定义一个动画效果的函数。
ul.offsetLeft是固定的,就是ul的偏移量。加上speed,然后通过定时器进行位移。
function Roll(distance){
clearInterval(ul.timer); //每次运行该函数都要清除之前的定时器
var speed = ul.offsetLeft < distance ? rate : (0-rate); //图片移动方向
ul.timer = setInterval(function(){
ul.style.left = ul.offsetLeft + speed + 'px'
var leave = distance - ul.offsetLeft; //用于判断距离目标点剩余的px值
// 接近目标点时的处理,滚动接近目标时直接到达,避免rate值设置不当时不能完整显示图片
if(Math.abs(leave) <= Math.abs(speed)){
clearInterval(ul.timmer)
ul.style.left = distance + 'px'
}
},20)
}
4.自动滚动
function autoRoll(){
picN++
cirN++
if(picN > len-1){ // 滚动完之后,如果当前图片下标等于图片的张数
ul.style.left = 0; // 改变left至真正的第一项处
picN = 1; // 从第二张开始显示
}
Roll(-picN*width)
if(cirN > len-1){ // 判断是否到了最后一个圆点
cirN = 0;
}
}
开始自动滚动
timer = setInterval(autoRoll,gaps)
5.触及小圆点时切换至对应图片
6.触及轮播图区域和离开该区域时
box.onmouseover = function(){
clearInterval(timer)
button.style.display = 'block'
}
box.onmouseout = function(){
timer = setInterVal(autoRun,gap)
button.style.display = 'none'
}