三者都是用于网络请求,但是不同维度
ajax: Asynchronous Javascript and XML
用javascript异步形式去操作XML
ajax流程步骤:
第一步:
var xhr = XMLHttpRequest();//这是个api
// 创建一个ajax对象,标准浏览器下。
ie6以下,ActiveXObject('Microsoft.XMLHTTP');
用异常错误处理机制来解决对象兼容问题。
第二步:
xhr.open('get','1.txt',true);
//open方法参数:
1,打开方式
get问题:
1,缓存:必须关闭浏览器再打开才刷新,
解决方法给url后面给一个现在时间或者随机数就解决问题
2,乱码,编码encodeURI
post问题:
1,post方式,数据放在send(username=betrs&age=21)方法里面作为参数传递
2,post方式没有缓存问题
2,地址
3,是否异步
true异步:非阻塞,前面的代码不会影响后面的代码的执行
false同步:阻塞,前面的代码会影响后面的代码的执行
设置请求头:
POST : 方式传递数据时要设置请求头
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
//声明发送数据的编码类型
第三步:
xhr.send();
//提交,发送请求
第四步:
xhr.onreadystatechange= function(){
//等待服务器返回内容
if(xhr.readystate == 4){
if(xhr.status == 200){
alert(xhr.responseText);
}else{
alert('出错了,Error:'+xhr.status);
};
};
};
onreadystatechange:当readystate的状态值改变的时候触发
readystate: ajax工作状态,该属性一共有四个值
0:(初始化)还没有调用open()方法
1:(载入)以调用send()方法,正在发送请求
2:(载入完成)send()方法完成,已收到全部响应内容
3:(解析)正在解析响应内容
4:(完成)响应内容解析完成,可以在客户端调用了
status:服务器状态,http状态码
responseText: ajax请求返回的内容就被存放到这个属性下面, 内容是字符串
responseXML:返回XML形式内容
当用responseText 获取到数据后,前端显示的是字符串,需要转成数组,方法如下:
function ajax1(url, successFn) {
const xhr = new XMLHttpRequest()
xhr.open("GET", url, false)
xhr.onreadystatechange = function () {
// 这里的函数异步执行,可参考之前 JS 基础中的异步模块
if (xhr.readyState == 4) {
if (xhr.status == 200) {
successFn(xhr.responseText)
}
}
}
xhr.send(null)
}
function ajax2(url) {//使用fetch Api实现ajax
return fetch(url).then(res => res.json())
}
是一个请求的第三方库
axios是通过promise实现对ajax技术的一种封装,就像jQuery实现ajax封装一样。
简单来说: ajax技术实现了网页的局部数据刷新,axios实现了对ajax的封装。
axios是ajax ajax不止axios。
jq的ajax
$.ajax({
url:"jq.php", //连接服务器
type:"POST", //传输方式
async:false,
dataType:'json',
data:{username:"hello"},//传送数据
success:function(data){ //执行回调函数
alert(data);
},
error:function(error){
console.log(error);
};
});
// 异常错误处理机制
try{
//代码尝试执行这个块中的内容,如果有错误,则会执行catch{},并且
传入错误信息参数
}catch(e){
}
//表单数据的提交
action:数据提交的地址,默认是当前页面
method:数据提交的方式,默认是get方式
1,get
把数据名称和数据值用=连接,如果有多个的话,那么他会把
多个数据组合用&进行连接,然后把数据放到url?后面,传到指定页面。
url长度限制的原因,我们不要通过get方式传递过多的数据
2,post
enctype:提交的数据格式,默认application/x-www-form-urlencoded
parse :可以把字符串转换成对应的对象
stringify :可以把一个对象转换成对应的字符串
防抖和节流?防抖和节流大概的思路?用在什么地方?
防抖
你先抖动着啥时候 停止了 在执行下一步
一个搜索输入框,等输入停止之后,再触发搜索,不停的话是不会搜索
<p>debounce</p>
搜索 <input id="input1">
<script>
function debounce(fn, delay = 200) {
let timer = 0//触发函数记录
//返回一个函数
return function () {
//连续触发就一直清除之前的timer,不是连续触发了 最后一个再执行 看图
// 点第2个的时候 第一个这个setTimeout 还没执行
if (timer) clearTimeout(timer)
//每次触发函数都会有个记录
timer = setTimeout(() => {
fn.apply(this, arguments) // 透传 this 和参数
timer = 0//还原0
}, delay)
}
}
const input1 = document.getElementById('input1')
input1.addEventListener('keyup', debounce(() => {
console.log('发起搜索', input1.value)
}), 300)
</script>
节流
<p>throttle</p>
<div id="div1" draggable="true" style="width: 100px; height: 50px; background-color: #ccc; padding: 10px;">
可拖拽
</div>
<script>
function throttle(fn, delay = 100) {
let timer = 0
return function () {
if (timer) return
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = 0
}, delay)
}
}
const div1 = document.getElementById('div1')
div1.addEventListener('drag', throttle((e) => {
console.log('鼠标的位置', e.offsetX, e.offsetY)
}))
</script>
相对于当前字体的大小;
根据响应式匹配 适配手机屏幕
不同的手机像素下可以设置html{font-size:110px;}根元素的字体大小
vw 屏幕宽度1%
vh 屏幕高度1%
对象方法
对象原型
构造函数
动态上下文回调函数
vue 生命周期 methods
tcp连接3次握手
比喻:第一次问张三在不在家;第二次张三说我在家;第三次我跟张三说你等着我马上过去;这时候张三才会等着你;
中间连接建立,数据传输;
四次挥手-关闭连接
比喻:告诉张三我没有东西了;张三告诉我说好的我知道了;张三把手头活搞完了告诉我说我这传输好了;我说好的我这边接受完毕了,可以了关闭了;
for of 遍历value for in 遍历index key
const arr = [10, 20, 30]
for (let val of arr) {
console.log(val)// 10 20 30
}
const str = 'abc'
for (let c of str) {
console.log(c)// abc
}
//遍历参数
function fn() {
for (let arg of arguments) {
console.log(arg)
}
}
// fn(100, 200, 'aaa')
//遍历DOM节点
const pList = document.querySelectorAll('p')
for (let p of pList) {
console.log(p)
}
适用与不同数据类型
遍历对象:for…in可以,for…of不可以
遍历Map Set :for…of可以 for…in不可以
遍历generator:for…of可以,for…in不可以
const obj = {
name: '双越',
city: '北京'
}
for (let val of obj) {
console.log(val) // 错误的
}
const set = new Set([10, 20, 30])
for (let n of set) {
console.log(n)
}
const map = new Map([
['x', 100],
['y', 200],
['z', 300]
])
for (let n of map) {
console.log(n)
}
function* foo() {
yield 10
yield 20
yield 30
}
for (let n of foo()) {
console.log(n)
}
用于可枚举enumrable数据,如对象,数组,字符串;得到key
用于可迭代Iterator数据,如数组,字符串,Map,Set ;得到Value
Iterator里面有next()方法
function createPromise(val) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(val)
}, 1000)
})
}
(async function () {
// 这一开始全部调用的话 不会延迟执行
const p1 = createPromise(100)
const p2 = createPromise(200)
const p3 = createPromise(300)
const res1 = await p1
console.log(res1)
const res2 = await p2
console.log(res2)
const res3 = await p3
console.log(res3)
const list = [p1, p2, p3]
// Promise.all(list).then(res => console.log(res))
for await (let res of list) {
console.log(res)
}
// ---------------------- 分割线 ----------------------
//延迟调用 1s后打印100 2s后打印200 3s后打印300
const res1 = await createPromise(100)
// console.log(res1)
const res2 = await createPromise(200)
// console.log(res2)
const res3 = await createPromise(300)
// console.log(res3)
const arr = [10, 20, 30]
for (let num of arr) {
const res = await createPromise(num)
console.log(res)
}
})()
-------------------
const sleep = (timeountMS) =>
new Promise((resolve) => {
setTimeout(resolve, timeountMS);
});
async function () {
await sleep(1000)
//1s后执行
$("#orderStatus").text("门票打印完成");
}
-clientWidth-clientHeight
-scrollWidth-scrollHeight
#container {
width: 300px;
height: 200px;
padding: 20px;
margin: 30px;
border: 5px solid #ccc;
box-sizing: border-box;
overflow: auto;
background-color: #fff;
}
const container = document.getElementById('container')
//padding+content+border
console.log('offsetHeight', container.offsetHeight)//200
console.log('offsetWidth', container.offsetWidth)//300
//padding+content
console.log('clientWidth', container.clientWidth)//290
console.log('clientHeight', container.clientHeight)//190
//padding+实际内容尺寸
console.log('scrollWidth', container.scrollWidth)//290
console.log('scrollHeight', container.scrollHeight)//190
DOM是一棵树,所有节点是Node;
Node是Element的基类
<p id="p1"><b>node</b> vs <em>element</em><!--注释--></p>
const p1 = document.getElementById('p1')
//Text(node vs ) Comment (<!--注释-->)不归element管
console.log(p1.children instanceof HTMLCollection)//true
console.log(p1.children instanceof NodeList)// false
console.log(p1.childNodes instanceof NodeList )//true
p1.children {0:b,1:em}
p1.childNodes{0:b,1:text,2:em,3:comment}
class Node {}
// document
class Document extends Node {}
class DocumentFragment extends Node {}
// 文本和注释
class CharacterData extends Node {}
class Comment extends CharacterData {}
class Text extends CharacterData {}
// elem
class Element extends Node {}
class HTMLElement extends Element {}
class HTMLDivElement extends HTMLElement {}
class HTMLInputElement extends HTMLElement {}
获取Node 和Element 的返回结果可能不一样
如elem.childNodes和elem.children不一样
前者会包含Text 和Comment节点,后者不会
扩展:类数组->数组
const arr1=Array.from(list);
const arr2=Array.prototype.slice.call(list);
const arr3=[…list]
computed 用于计算产生新的数据
watch 用于监听现有的数据
*computed 有缓存 methods 没有缓存
计算属性默认仅能通过计算函数得出结果。当你尝试修改一个计算属性时,
你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的
属性,你可以通过同时提供 getter 和 setter 来创建:
export default {
data() {
return {
firstName: 'John',
lastName: 'Doe'
}
},
computed: {
fullName: {
// getter
get() {
return this.firstName + ' ' + this.lastName
},
// setter
set(newValue) {
// 注意:我们这里使用的是解构赋值语法
[this.firstName, this.lastName] = newValue.split(' ')
}
}
}
}
现在当你再运行 this.fullName = 'John Doe' 时,setter 会被调用而 this.firstName 和 this.lastName 会随之更新。
emits:['showMsg']
methods:{
clickHandle(){
this.$emit('showMsg','hello word')
}
}
-----------------------自定义事件
Vue2 :new Vue()=>event on off event
Vue3 引入第三方自定义事件 event-emitter
---------------------------$attrs 透传
类似多个参数 $props
<template>
<p>Level1</p>
<Level2
:a="a"
:b="b"
:c="c"
@getA="getA"
@getB="getB"
@getC="getC"
></Level2>
</template>
<template>
<p>Level2</p>
<Level3
:x="x"
:y="y"
:z="z"
@getX="getX"
@getY="getY"
@getZ="getZ"
v-bind="$attrs" //把level1的abc@getA @getB @getC 都塞给了C
></Level3>
</template>
<template>
<p>Level3</p>//当只有 一个标签的时候 会继承属性 a b c inheritAttrs: false, 如果有Helloword 就不用写了
<HelloWorld msg="hello 双越" ref="hello1"/>
</template>
----------------------------$parent
this. p a r e n t 获 取 父 组 件 t h i s . parent获取父组件 this. parent获取父组件this.refs 获取子组件
直接调用父级的方法
this.$parent.getX()
直接调用子组件的方法
console.log(this.$refs.hello1.name)
----------------------------provide/inject
多层级传递
--------------level1
provide: {
info: 'aaa'
}
---------------level3
<template>
<p>Level3 {{info}}</p>
</template>
<script>
export default {
name: 'Level3',
inject: ['info']
}
</script>
开启严格模式
‘use strict’ //全局开启
function fn(){
‘use strict’ //某个函数开启
}
------------------全局变量必须声明
n=10
---------------------禁止使用with
const obj={x:100,y:200}
with(obj){
console.log(x,y)
}
------------------创建eval 作用域
var x=20;
eval(`var x=30;console.log(x)`)//30
console.log(x)//20
-----------------禁止this指向window
fn()
function fn(){
console.log(this)//严格模式是未定义
}
-------------- 函数参数不能重名
function fn(a,a,c){}
a网页 通过 script 请求b网页 b网页直接通过字符串 返回a网页当js去执行
服务端设置
什么是垃圾回收? 标记清除,从window根开始遍历,找到保留,找不到清除
//执行完之后 会回收
function fn(){
const a="aa"
}
fn()
//全局引用的 不会被回收
function fn2() {
const obj = { x: 100 }
window.obj = obj
}
fn2()
function getDataFns() {
//只要这个 data在外面有应用 就不会销毁
const data = {} // 闭包
return {
get(key) {
return data[key]
},
set(key, value) {
data[key] = value
}
}
}
const { get, set } = getDataFns()
set('x', 100)
get('x')
不是;只有非预期情况是泄漏;闭包是预期的;
闭包数据不能被垃圾回收,
<script>
export default {
name: 'Memory Leak Demo',
data() {
return {
arr: [10, 20, 30], // 数组 对象
}
},
methods: {
printArr() {
console.log(this.arr)
}
},
mounted() {
window.addEventListener('resize', this.printArr)
// 自定义事件也是这样
},
// Vue2 - beforeDestroy
beforeUnmount() {
window.removeEventListener('resize', this.printArr)
},
}
</script>
const wMap = new WeaMap() // 弱引用
function fn1() {
const obj = { x: 100 }// weakMap引用一定会销毁
wMap.set(obj, 100) // weakMap 的 key 只能是引用类型
}
fn1()
宏任务 ,setTimeout setInterval网络请求
微任务,如promise async/await
微任务在下一轮DOM渲染之前执行,宏任务在之后执行
console.log('start')//1
setTimeout(() => {
console.log('timeout')//4
})
Promise.resolve().then(() => {
console.log('promise then')//3
})
console.log('end')//2
-----------微任务 渲染页面之前触发 宏任务是页面之后触发
const p = document.createElement('p')
p.innerHTML = 'new paragraph'
document.body.appendChild(p)
const list = document.getElementsByTagName('p')
console.log('length----', list.length)
console.log('start')
// 渲染之后
setTimeout(() => {
const list = document.getElementsByTagName('p')
console.log('length on timeout----', list.length) // 2
alert('阻塞 timeout')
})
// 渲染之前
Promise.resolve().then(() => {
const list = document.getElementsByTagName('p')
console.log('length on promise.then----', list.length) // 2
alert('阻塞 promise')
})
console.log('end')
单线程和异步(异步是单线程的解决方案)
console.log('start')
setTimeout(() => {
console.log('timeout')
},1000)
Promise.resolve().then(() => {
console.log('promise then')
})
console.log('end')
// ajax(url, fn) // 300ms
// Event Loop 继续监听... 如果ajax300ms之后响应,那就是300ms之后加入宏任务;
//setimeout 1000ms之后 是1000ms放入宏任务
// 宏任务 MarcoTask Queue
// () => {
// console.log('timeout')
// }
// fn
//js是单线程 所以是 先同步-->微任务--->DOM渲染-->宏任务
// DOM 渲染
// 微任务 MicroTask Queue
// () => {
// console.log('promise then')
// }
console.info('start')
setImmediate(() => {//宏任务
console.info('setImmediate')4
})
setTimeout(() => {
console.info('timeout')3
})
Promise.resolve().then(() => {
console.info('promise then')2
})
// process.nextTick(() => {
// console.info('nextTick')//1
// })
console.info('end')
o(n) 时间复杂度
const arr = []
for (let i = 0; i < 100 * 10000; i++) {
arr.push(i)
}
const length = arr.length
console.time('for')
let n1 = 0
for (let i = 0; i < length; i++) {
n1++
}
console.timeEnd('for') // 3.7ms
console.time('forEach')
let n2 = 0
arr.forEach(() => n2++)
console.timeEnd('forEach') // 15.1ms
是一种web服务的架构风格。
看 Url 就知道要什么
看 http method 就知道干什么
看 http status code 就知道结果如何
解决方式:安装 “babel-polyfill” 即可。
命令:npm install --save-dev babel-polyfill
在入口main.js文件引入:import ‘babel-polyfill’
最后一步,在build文件夹下找到webpack.base.conf.js.修改入口方式:
entry: {
app: [“babel-polyfill”, “./src/main.js”]
}
最后,再依赖一个插件解决ES6/ES7高级语法兼容
npm install --save-dev babel-preset-es2015-ie
如果根目录下缺少文件.babelrc,新建一个,如下:
{
“presets”: [
[“env”, {
“modules”: false,
“targets”: {
“browsers”: [“> 1%”, “last 2 versions”, “not ie <= 8”]
}
}],
“stage-2”
],
“plugins”: [“transform-runtime”],
“env”: {
“test”: {
“presets”: [“env”, “stage-2”],
“plugins”: [“istanbul”]
}
}