一个是定义属性,一个是代理
Object.defineProperty()
define 定义 property 属性
(obj , prop , descriptor)
description 叙述、表述
descript 动词
descriptor 描述项集合
一个是定义属性,一个是代理
define 定义 property 属性
(obj , prop , descriptor)
description 叙述、表述
descript 动词
descriptor 描述项集合
Vue3 是一个革命性的版本,它不仅带来了性能的提升,更重要的是引入了组合式 API,彻底改变了我们编写 Vue 组件的方式。本文将深入探讨 Vue3 的核心特性,并通过实际案例展示如何更好地使用这些特性。
组合式 API 是 Vue3 最重要的特性之一,它解决了 Vue2 中代码组织的问题,使得逻辑复用和代码组织变得更加灵活。
setup()
是组合式 API 的入口点,它在组件实例创建之前执行setup
在组件实例创建之前执行,所以无法访问 this
setup
函数接收两个参数:props
和 context
import { defineComponent } from 'vue'
export default defineComponent({
props: {
title: String
},
setup(props, context) {
// props 是响应式的,但不要解构它
console.log(props.title)
// context 包含 attrs, slots, emit 等
const { attrs, slots, emit } = context
return {
// 返回的内容会暴露给模板
}
}
})
Vue3 的响应式系统基于 Proxy 实现,提供了更强大的响应式能力。
import { ref, watchEffect } from 'vue'
export default {
setup() {
// ref 用于基本类型的响应式
const count = ref(0)
// 访问 ref 的值需要使用 .value
console.log(count.value) // 0
// 在模板中会自动解包,不需要 .value
const increment = () => {
count.value++
}
// watchEffect 会自动追踪依赖
watchEffect(() => {
console.log('count is:', count.value)
})
return {
count,
increment
}
}
}
import { reactive, computed, watch } from 'vue'
export default {
setup() {
// reactive 用于对象的响应式
const state = reactive({
count: 0,
double: computed(() => state.count * 2),
history: []
})
// 监听单个属性
watch(
() => state.count,
(newValue, oldValue) => {
state.history.push({
newValue,
oldValue,
timestamp: new Date()
})
}
)
// 深度监听对象
watch(
() => state,
(newValue) => {
console.log('state changed:', newValue)
},
{ deep: true }
)
return {
state
}
}
}
Vue3 的生命周期钩子都带有 on
前缀,并且只能在 setup
中使用:
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
onErrorCaptured
} from 'vue'
export default {
setup() {
onBeforeMount(() => {
console.log('组件挂载前')
})
onMounted(() => {
console.log('组件已挂载')
// 可以在这里进行 DOM 操作
})
onBeforeUpdate(() => {
console.log('组件更新前')
})
onUpdated(() => {
console.log('组件已更新')
})
onBeforeUnmount(() => {
console.log('组件卸载前')
})
onUnmounted(() => {
console.log('组件已卸载')
// 可以在这里清理定时器、事件监听等
})
onErrorCaptured((err, instance, info) => {
console.error('捕获到错误:', err)
return false // 阻止错误继续传播
})
}
}
import { reactive, toRefs, toRef } from 'vue'
export default {
setup() {
const state = reactive({
count: 0,
name: 'Vue3'
})
// toRefs 将整个对象转换为响应式引用
const { count, name } = toRefs(state)
// toRef 创建单个属性的响应式引用
const countRef = toRef(state, 'count')
// 这些引用都是响应式的
console.log(count.value) // 0
console.log(name.value) // 'Vue3'
return {
count,
name,
countRef
}
}
}
import {
isRef,
unref,
isReactive,
isReadonly,
markRaw
} from 'vue'
export default {
setup() {
const count = ref(0)
// 检查是否是 ref
console.log(isRef(count)) // true
// 获取 ref 的值,如果不是 ref 则返回原值
console.log(unref(count)) // 0
const state = reactive({})
// 检查是否是响应式对象
console.log(isReactive(state)) // true
// 检查是否是只读对象
console.log(isReadonly(readonly(state))) // true
// 标记对象为非响应式
const raw = markRaw({ count: 0 })
}
}
自定义 Hook 是组合式 API 最强大的特性之一,它让我们能够轻松地复用逻辑。
import { toRefs, reactive, onMounted, onUnmounted } from 'vue'
function useMousePosition() {
const state = reactive({
x: 0,
y: 0,
isMoving: false
})
const updateMouse = (e: MouseEvent) => {
state.x = e.pageX
state.y = e.pageY
state.isMoving = true
// 使用 requestAnimationFrame 优化性能
requestAnimationFrame(() => {
state.isMoving = false
})
}
onMounted(() => {
document.addEventListener('mousemove', updateMouse)
})
onUnmounted(() => {
document.removeEventListener('mousemove', updateMouse)
})
return toRefs(state)
}
import { ref, onMounted } from 'vue'
interface UseFetchOptions {
immediate?: boolean
onSuccess?: (data: any) => void
onError?: (error: Error) => void
}
function useFetch<T>(url: string, options: UseFetchOptions = {}) {
const data = ref<T | null>(null)
const error = ref<Error | null>(null)
const loading = ref(false)
const fetchData = async () => {
loading.value = true
try {
const response = await fetch(url)
data.value = await response.json()
options.onSuccess?.(data.value)
} catch (e) {
error.value = e as Error
options.onError?.(e as Error)
} finally {
loading.value = false
}
}
if (options.immediate) {
onMounted(fetchData)
}
return {
data,
error,
loading,
fetchData
}
}
// 使用示例
export default {
setup() {
const { data, error, loading, fetchData } = useFetch('/api/users', {
immediate: true,
onSuccess: (data) => {
console.log('数据加载成功:', data)
}
})
return {
data,
error,
loading,
fetchData
}
}
}
Teleport 是 Vue3 新增的组件,用于将组件的内容传送到 DOM 树的其他位置。这在处理模态框、弹出框等场景特别有用。
<template>
<div class="app">
<button @click="showModal = true">打开模态框</button>
<Teleport to="body">
<div v-if="showModal" class="modal-overlay" @click="closeModal">
<div class="modal-content" @click.stop>
<h2>{{ title }}</h2>
<p>{{ content }}</p>
<div class="modal-footer">
<button @click="confirm">确认</button>
<button @click="closeModal">取消</button>
</div>
</div>
</div>
</Teleport>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
props: {
title: {
type: String,
default: '提示'
},
content: {
type: String,
required: true
}
},
setup(props, { emit }) {
const showModal = ref(false)
const closeModal = () => {
showModal.value = false
emit('close')
}
const confirm = () => {
emit('confirm')
closeModal()
}
return {
showModal,
closeModal,
confirm
}
}
}
</script>
<style scoped>
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
background: white;
padding: 20px;
border-radius: 8px;
min-width: 300px;
}
.modal-footer {
margin-top: 20px;
text-align: right;
}
.modal-footer button {
margin-left: 10px;
}
</style>
Vue3 在性能方面有显著提升
import { shallowRef, shallowReactive, markRaw } from 'vue'
export default {
setup() {
// 浅层响应式,只跟踪顶层属性
const shallowState = shallowReactive({
user: {
name: 'Vue3',
address: {
city: 'Beijing'
}
}
})
// 浅层 ref,只跟踪 .value 的变化
const shallowRef = shallowRef({
count: 0
})
// 标记为非响应式
const staticData = markRaw({
config: {
theme: 'dark'
}
})
}
}
import { defineAsyncComponent } from 'vue'
export default {
components: {
// 异步组件
AsyncComponent: defineAsyncComponent(() =>
import('./AsyncComponent.vue')
),
// 带加载状态的异步组件
AsyncComponentWithLoading: defineAsyncComponent({
loader: () => import('./AsyncComponent.vue'),
loadingComponent: LoadingComponent,
errorComponent: ErrorComponent,
delay: 200,
timeout: 3000
})
}
}
Vue3 使用 TypeScript 重写,提供了更好的类型支持。
import { defineComponent, PropType } from 'vue'
interface User {
id: number
name: string
age: number
}
export default defineComponent({
props: {
// 基础类型
title: {
type: String,
required: true
},
// 对象类型
user: {
type: Object as PropType<User>,
required: true
},
// 数组类型
items: {
type: Array as PropType<User[]>,
default: () => []
}
},
setup(props) {
// props 类型会被正确推导
console.log(props.user.name)
return {}
}
})
import { ref, computed } from 'vue'
interface State {
count: number
name: string
}
export default defineComponent({
setup() {
// ref 类型
const count = ref<number>(0)
// reactive 类型
const state = reactive<State>({
count: 0,
name: 'Vue3'
})
// computed 类型
const double = computed<number>(() => count.value * 2)
return {
count,
state,
double
}
}
})
import { onRenderTracked, onRenderTriggered } from 'vue'
export default {
setup() {
onRenderTracked((event) => {
console.log('组件渲染追踪:', {
target: event.target,
type: event.type,
key: event.key
})
})
onRenderTriggered((event) => {
console.log('组件渲染触发:', {
target: event.target,
type: event.type,
key: event.key,
newValue: event.newValue,
oldValue: event.oldValue
})
})
}
}
import { onMounted, onUnmounted } from 'vue'
export default {
setup() {
let startTime
onMounted(() => {
startTime = performance.now()
})
onUnmounted(() => {
const endTime = performance.now()
console.log(`组件生命周期: ${endTime - startTime}ms`)
})
}
}
// composables/useCounter.js
import { ref, computed } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
function decrement() {
count.value--
}
return {
count,
double,
increment,
decrement
}
}
// components/Counter.vue
import { useCounter } from '../composables/useCounter'
export default {
setup() {
const { count, double, increment, decrement } = useCounter()
return {
count,
double,
increment,
decrement
}
}
}
// store/counter.js
import { reactive } from 'vue'
export const store = reactive({
count: 0,
increment() {
this.count++
}
})
// components/Counter.vue
import { store } from '../store/counter'
export default {
setup() {
return {
store
}
}
}
从 Vue2 迁移到 Vue3 时,建议采用渐进式迁移策略:
@vue/composition-api
插件在 Vue2 中提前使用组合式 APIdefineComponent
包装组件获得更好的类型推导Vue.observable
Vue3 带来了许多激动人心的新特性,特别是组合式 API 的引入,使得代码组织更加灵活,逻辑复用更加方便。通过合理使用这些特性,我们可以构建出更易维护、性能更好的应用。
Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用程序的框架。它将 Chromium 和 Node.js 合并到同一个运行时环境中,使开发者能够使用 Web 技术构建桌面应用。
Electron 使用 IPC (进程间通信) 在进程之间进行通讯,和 Chromium 完全一致。
ipcMain (主进程)
ipcRenderer (渲染进程)
主进程 (main.js):
const { ipcMain } = require('electron')
// 监听来自渲染进程的消息
ipcMain.on('message-to-main', (event, arg) => {
console.log(arg) // 打印 "Hello from renderer"
// 回复消息给渲染进程
event.reply('message-from-main', 'Hello from main process')
})
渲染进程 (renderer.js):
const { ipcRenderer } = require('electron')
// 发送消息到主进程
ipcRenderer.send('message-to-main', 'Hello from renderer')
// 监听来自主进程的回复
ipcRenderer.on('message-from-main', (event, arg) => {
console.log(arg) // 打印 "Hello from main process"
})
npm init
npm install electron --save-dev
npm install nodemon --save-dev
"start": "nodemon --watch main.js --exec 'electron .'"
main.js : 创建窗口 - BrowserWindow
const {app, BrowserWindow} = require('electron')
app.on('ready', () => {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true
}
})
mainWindow.loadFile('./index.html')
// 打开开发者工具
mainWindow.webContents.openDevTools()
})
// 处理窗口关闭事件
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
上下文隔离
contextIsolation: true
preload
脚本安全地暴露 API沙箱模式
内容安全策略 (CSP)
进程间通信安全
主进程调试
--inspect
参数启动应用渲染进程调试
webContents.openDevTools()
npm install electron-builder --save-dev
{
"build": {
"appId": "com.example.app",
"mac": {
"category": "public.app-category.utilities"
},
"win": {
"target": "nsis"
},
"linux": {
"target": "AppImage"
}
}
}
electron-builder build
内存管理
webContents.clearCache()
启动优化
app.commandLine.appendSwitch('disable-gpu')
渲染进程优化
requestIdleCallback
白屏问题
进程通信失败
打包问题
uni-app 中 css 关于 calc()函数计算无效问题
原本以为uni-app不支持calc计算,后来发现:
计算符:+ - * /
计算符前后都需要空格,否则计算无效
.tets{
height: calc(var(--status-bar-height) + 10px);
}
SSH连接报错:Permission denied, please try again
当使用 SSH 登录云服务器 ECS (Elastic Compute Server) Linux 服务器时,如果是 root 用户,即便正确输入了密码,也会出现类似如下错误信息。
Permission denied, please try again. SSH 服务器拒绝了密码,请再试一次。 但非root用户可以正常登录,而且root用户通过 管理终端 登录也正常。
通过 管理终端 (VNC连接)进入系统。 通过 cat 等指令查看 /etc/ssh/sshd_config 中是否包含类似如下配置: PermitRootLogin no
PermitRootLogin yes 使用如下指令重启 SSH 服务: service sshd restart
github.com/snabbdom/snabbd om
简洁强大的 vdom 库
Vue 参考它实现的 vdom 和 diff
Vue3 重写了 vdom 的代码,优化了性能,但是 vdom 的基本理念不变
h函数、vnode数据结构、patch函数
patchVnode函数:新旧都有 children,执行update。新有旧无,执行add。新无旧有,执行remove
updateChildren函数
第一个参数:标签
第二个参数:属性
第三个参数:子元素
patch 函数 渲染 vnode
const vnode = h('ul#list',{},[
h('li.item',{},'Item1'),
h('li.item',{},'Item2')
])
const = document.getElementById('container')
patch(container,vnode) //初次渲染
const newVnode = h('ul#list',{},[
h('li.item',{},'Item')
])
patch(vnode,newVnode) //dom更新
JS 的 with 语法
vue template complier 将模板编译为 render 函数
执行 render 函数生成 vnode
vue的模板不是 html,有指令,插值,js表达式,判断,循环
因此,模板一定是转换为某种 js 代码,即编译模板
vue组件可以用 render 代替 template
vue-template-compiler
模板 通过 compiler 编译成 render 函数,执行函数生成 vnode,再到渲染和更新
基于 vnode 再执行 patch 和 diff
这里面的 _c 等同于 createElement 等同于 h函数
const compiler = require('vue-template-compiler')
// 插值
const template = `<p>{{message}}</p>`
with(this){return createElement('p',[createTextVNode(toString(message))])}
// h -> vnode
// createElement -> vnode
// 表达式
const template = `<p>{{flag ? message : 'no message found'}}</p>`
with(this){return _c('p',[_v(_s(flag ? message : 'no message found'))])}
// 属性和动态属性
const template = `
<div id="div1" class="container">
<img :src="imgUrl"/>
</div>
`
with(this){return _c('div',
{staticClass:"container",attrs:{"id":"div1"}},
[
_c('img',{attrs:{"src":imgUrl}})])}
// 条件
const template = `
<div>
<p v-if="flag === 'a'">A</p>
<p v-else>B</p>
</div>
`
with(this){return _c('div',[(flag === 'a')?_c('p',[_v("A")]):_c('p',[_v("B")])])}
// 循环
const template = `
<ul>
<li v-for="item in list" :key="item.id">{{item.title}}</li>
</ul>
`
with(this){return _c('ul',_l((list),function(item){return _c('li',{key:item.id},[_v(_s(item.title))])}),0)}
// 事件
const template = `
<button @click="clickHandler">submit</button>
`
with(this){return _c('button',{on:{"click":clickHandler}},[_v("submit")])}
// v-model
const template = `<input type="text" v-model="name">`
// 主要看 input 事件
with(this){return _c('input',{directives:[{name:"model",rawName:"v-model",value:(name),expression:"name"}],attrs:{"type":"text"},domProps:{"value":(name)},on:{"input":function($event){if($event.target.composing)return;name=$event.target.value}}})}
// render 函数
// 返回 vnode
// patch
// 编译
const res = compiler.compile(template)
console.log(res.render)
// 从 vue 源码中找到缩写函数的含义
function installRenderHelpers (target) {
target._o = markOnce;
target._n = toNumber;
target._s = toString;
target._l = renderList;
target._t = renderSlot;
target._q = looseEqual;
target._i = looseIndexOf;
target._m = renderStatic;
target._f = resolveFilter;
target._k = checkKeyCodes;
target._b = bindObjectProps;
target._v = createTextVNode;
target._e = createEmptyVNode;
target._u = resolveScopedSlots;
target._g = bindObjectListeners;
target._d = bindDynamicKeys;
target._p = prependModifier;
}
//使用setup() 替代
beforecreate -> use setup()
created -> use setup()
//前面加on
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onbeforeUpdate
updated -> onUpdated
activated -> onActivated
deactivated -> onDeactivated
errorCaptured -> onErrorCaptured
//更改名称
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
//新加入,主要用于开发阶段调试使用
onRenderTracked
onRenderTriggered
ref
toRef
针对一个响应式对象(reactive 封装)的 prop
创建一个 ref,具有响应式
两者保持引用关系
toRef 如果用于普通对象(非响应式对象),产出的结果不具备响应式
const state = reactive({
age:10,
name:'xx'
})
const ageRef = toRef(state,'age') //单个
//修改其一都会联动
state.age = 20
ageRef.value = 30
toRefs
将响应式对象 (reactive 封装)转换为普通对象
对象的每个 prop 都是对应的 ref
两者保持引用关系
//不能直接结构使用,需要 toRefs
const state = reactie({
age:10,
name:'xx'
})
const stateAsRefs = toRefs(state) //整个
const {age:ageRef,name:nameRef} = stateAsRefs //每个属性 都是ref响应式对象
return {
ageRef,
nameRef
}
return stateAsRefs
return {
...stateAsRefs
}
return toRefs(state)
最佳使用方式
6-9
hash
hash 变化会触发网页跳转,即浏览器的前进和后退
hash 变化不会刷新页面,SPA 必需的特点
hash 永远不会提交到 server 端
window.onhashchange
window.onhashchange = (event) =>{
console.log('old url:',event.oldURL)
console.log('new url:',event.newURL)
console.log('hash:',event.hash)
}
H5 history
用 url 规范的路由,但跳转时不刷新页面
history.pushState 向浏览器历史添加了⼀个状态(增加⼀个记录)
history.replaceState 把当前的页⾯的历史记录替换掉
window.onpopstate
// 页面初次加载,获取 path
document.addEventListener('DOMContentLoaded', () => {
console.log('load', location.pathname)
})
// 打开一个新的路由
// 用 pushState 方式,浏览器不会刷新页面
document.getElementById('btn1').addEventListener('click', () => {
const state = { name: 'page1' }
console.log('切换路由到', 'page1')
history.pushState(state, '', 'page1') // 重要
})
// 监听浏览器前进、后退
window.onpopstate = (event) => { // 重要
console.log('onpopstate', event.state, location.pathname)
}
<User v-bind="$props" />
<slot :user="user">
<template v-slot='slotProps'>
接收基础知识学习概览
BFC 块级格式化上下文,一块独立渲染区域,内部元素的渲染不会影响边界以外的元素
圣杯布局和双飞翼布局
clearfix
.clearfix{
clear: both;
content: '';
display: block;
width: 0;
height: 0;
visibility: hidden;
}
flex 布局
值类型 和 引用类型
null 特殊引用类型,指针指向为空地址
null == undefined // true
// 除了 == null 之外,其他一律都用 ===
const obj = {x:100}
if(obj.a == null){}
// 这里相当于:
// if (obj.a === null || obj.a === undefined){}
Typeof 能准确判断值类型(除了null),引用类型只能判断 function 和 object
对于
null
来说,虽然它是基本类型,但是会显示object
,这是一个存在很久了的Bug
typeof null // 'object'
typeof NaN // 'number'
typeof dd // 'undefined' dd is not defined
10 && 0 // 10
'' || 'aaa' // 'aaa'
!window.aa // true
在
JS
的最初版本中,使用的是32
位系统,为了性能考虑使用低位存储了变量的类型信息,000
开头代表是对象,然而null
表示为全零,所以将它错误的判断为object
。虽然现在的内部类型判断代码已经改变了,但是对于这个Bug
却是一直流传下来。
深拷贝
function deepClone(obj){
if(typeof(obj)!=='object' || obj==null) return obj;
let copy = obj instanceof Array ? [] : {}
for(let key in obj){
if(obj.hasOwnProperty(key)){
copy[key] = deepClone(obj[key])
}
}
return copy
}
类型判断 instanceof
xiaoming instanceof Student // true
xiaoli instanceof People // true
[] instanceof Array // true
[] instanceof Object // true
{} instanceof Object // true
JS它本身是基于原型继承的语言
hasOwnProperty
实例化对象的隐式原型 === 类(class)的显示原型
prototype
__proto__
__proto__
指向对应 class 的 prototype
xiaoming.__proto__ === Student.prototype
__proto__
中查找Student.prototype.__proto__ === People.prototype
简易 Jquery
class jQuery {
constructor(selector) {
const result = document.querySelectorAll(selector)
const length = result.length
for (let i = 0; i < length; i++) {
this[i] = result[i]
}
this.length = length
this.selector = selector
}
get(index) {
return this[index]
}
each(fn) {
for (let i = 0; i < this.length; i++) {
const elem = this[i]
fn(elem)
}
}
on(type, fn) {
return this.each(elem => {
elem.addEventListener(type, fn, false)
})
}
// 扩展很多 DOM API
}
// 插件
jQuery.prototype.dialog = function (info) {
alert(info)
}
// “造轮子”
class myJQuery extends jQuery {
constructor(selector) {
super(selector)
}
// 扩展自己的方法
addClass(className) {
}
style(data) {
}
}
// const $p = new jQuery('p')
// $p.get(1)
// $p.each((elem) => console.log(elem.nodeName))
// $p.on('click', () => alert('clicked'))
作用域和自由变量
自由变量
闭包
所有的自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方!!!
function print(fn){
const a = 200
fn()
}
const a = 100
function fn(){
console.log(a)
}
print(fn) // 100
常规函数中的 this 取什么样的值是在函数执行时确认,不是在函数定义的时候确认的
对于箭头函数,this
关键字指向的是它当前周围作用域(简单来说是包含箭头函数的常规函数,如果没有常规函数的话就是全局对象),这个行为和常规函数不同。
// 模拟 bind
Function.prototype.bind1 = function () {
// 将参数拆解为数组
const args = Array.prototype.slice.call(arguments)
// 获取 this(数组第一项)
const t = args.shift()
// fn1.bind(...) 中的 fn1
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.bind1({x: 100}, 10, 20, 30)
const res = fn2()
console.log(res)
网络请求
定时任务
Event Loop
Promise
then 和 catch 改变状态
async / await
async / await 和 Promise 的关系
执行 async 函数,返回的是 Promise 对象
await 相当于 Promise 的 then
try...catch 可捕获异常,代替了 Promise 的 catch
async function fn(){
return 100;
}
(async function(){
const a = fn();
const b = await fn();
})()
// a 是返回的 promise 100
// b 是 then 返回的值 100
for - of
宏任务和微任务
event loop 和 DOM 渲染
Browser Object Model 浏览器操作相关
事件绑定
addEventListener
通用的事件绑定函数
function bindEvent(elem,type,fn){
elem.addEventListener(type,fn)
}
event.preventDefault() 阻止默认行为
事件冒泡
事件代理
var url = "server.php"; //设置请求的地址
var xhr = XMLHttpRequest(); //实例化XMLHttpRequest对象
xhr.open("POST", url, true); //建立间接,要求异步响应
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); //设置为表单方式提交
xhr.onreadystatechange = function () { //绑定响应状态事件监听函数
if (xhr.readyState == 4) { //监听readyState状态
if (xhr.status == 200 || xhr.status == 0) { //监听HTTP状态码
console.log(xhr.responseText); //接收数据
}
}
}
xhr.send(data数据);
Fetch
跨域
<img/>
可用于统计打点,可使用第三方统计服务<link/><script>
可使用CDN,CDN一般都是外域<script>
可使用JSONPaxios
前端存储
1xx 服务器收到请求
2xx 请求成功,如200
3xx 重定向,如302
4xx 客户端错误,如404
5xx 服务端错误,如500
200 成功
301 永久重定向(配合location,浏览器自动处理)
302 临时重定向(配合location,浏览器自动处理)
304 资源未被修改
404 资源未找到
403 没有权限
500 服务器错误
504 网关超时
强缓存:Cache-Control --> max-age、no-cathe
协商缓存:Last-Modified -->
命中缓存,返回 304 资源未被修改
关于缓存
缓存策略(强制缓存+协商缓存)
强制缓存
协商缓存(对比缓存)
服务端缓存策略(服务端来判断一个资源是不是可以被缓存,或者是不是可以用缓存,不是缓存在服务端)
服务端判断客户端资源,是否和服务端资源一样
304 资源未被修改
资源标识
刷新操作方式,对缓存的影响
git status #查看文件修改状态
git checkout -b dev #新建并切换到该分支
git checkout master #切换分支
git branch #查看分支列表
#分支合并
git fetch #拉取所有分支
移动端h5
windows:fiddler
mac:Charles
模块化就是一个导入和导出的过程
ES6:
// a.js
export const num = 123;
export function fn(){};
// 导入
import {const} from './a.js'
// b.js default
export default {
name : 'xxx'
}
import n from './b.js'
ssh root@192.168.xx.xx #登录
ls #查看文件夹
ls -a #查看所有包含隐藏 -a = all linux下 .开头的都是隐藏文件
ll #看列表形式的文件夹
clear #清屏
mv a.html b.html #修改文件名、移动文件
cp a.js a1.js #拷贝
rm #删文件
rm -rf #删文件夹
touch d.js #新建文件
vi d.js #新建文件并打开 i 编辑插入、 Esc + :wq 保存并退出、:q!不保存直接退出
cat d.js #查看文件
head d.js #打印出文件前面几行
tail d.js #打印末尾几行
grep "babel" package.json #查找文件内容
从输入url到渲染出页面的整个过程
加载过程
渲染过程
<script>
则暂停渲染XSS 跨站请求攻击
<script>
脚本,获取cookie,发送到我的服务器<
变为 <
/ >
变为 >
XSRF 跨站请求伪造
一封电子邮件,邮件正文隐藏着 <img src="xxx.com/pay?id=100">
,你查看邮件,就帮我购买了这个商品
iframe
使用 post 接口
增加验证,例如密码,短信验证码,指纹等
全等函数:isEqual
[10,20,30].map(parseInt) => [10,NaN,NaN]
jsonp是通过script标签发送请求,并通过回调函数的形式执行
ajax是通过XMLHttpRequest
函数声明会提升 function fn(){}
函数表达式没有提升 const fn = function(){}
函数声明会在代码执行前预加载,而函数表达式不会
try catch
window.onerror
function queryToObj(){
let res = {}
let query = location.search.substr(1)
query.split('&').forEach(item=>{
let s = item.split('=')
res[s[0]] = s[1]
})
return res
}
function queryToObj(){
let res = {}
const list = new URLSearchParams(location.search)
list.forEach((val,key)=>{
res[key] = val
})
return res
}
function animate(){
curWidth = curWidth + 1
if(curWidth < maxWidth){
window.requestAnimationFrame(animate)
}
}
animate()
原则:多实用内存,缓存,减少计算,减少网络请求
方向:加载页面,页面渲染,页面操作流畅度
全局函数:绑在全局对象上,可能会引发命名冲突,或者数据不安全
NameSpace:封装成对象,减少了全局变量,解决了命名冲突,但是外部可以修改模块内部的数据
匿名函数自调用:通过闭包的方式向外暴露接口,不太好处理模块之间的依赖关系
文件模块化:
- CommonJS
- AMD
- UMD (前两种的兼容)
-
原始值 -> 基本类型
引用值