let a = new Object()
=let a = Object()
=let a = {}
都会创建一个新对象
new
运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。
function Person(name) { // 构造函数Person()
this.name = name;
// this.prototype = Object
}
const a = new Person('ycl');
创建一个空的JavaScript 对象,即{}
– 调用构造函数Object()
const a = {};
设置该空对象的原型__proto__
,为构造函数的原型对象prototype
– 实现原型继承
a.__proto__ = Person.prototype = Object; // true
__proto__
就是其构造函数的原型对象prototype
将this
指向空对象并执行函数体;
a.name = 'ycl';
a.constructor = f Person(name)
判断构造函数的返回值,以决定最终返回结果 – 返回新对象
返回基础数据类型,则忽略返回值
function Person(name) {
this.name = name;
return 666;
}
const a = new Person('ycl');
// {name:'ycl'}
返回引用数据类型(return的返回),则new操作符无效,返回的是return内容
function Person(name) {
this.name = name;
return { // Object,Array,Function,Data...
age: 18
};
}
const a = new Person('ycl');
// {age:18}
闭包是什么
如何生成闭包
闭包的特性
缺点:
优点:
避免全局污染
延长生命周期
function outer() {
var a = 1;
function inner() {
console.log(a);
}
return inner;
}
var b = outer();
JavaScript中,
class
是关键字,但也只是语法糖。JavaScript 仍然是基于原型的。几乎所有 JavaScript 中的对象都是位于原型链顶端的
Object
的实例。
每个实例对象(object)都有一个私有属性(称之为 proto)指向它的构造函数的原型对象(prototype)
该原型对象也有一个自己的原型对象(proto),层层向上直到一个对象的原型对象为 null
理解 p 所在的原型链
p
实例对象 (对象)Person {name: 'ycl'}
p.__proto__
实例对象的原型 类似(指针){constructor: ƒ Person(name)}
Person.prototype
实例对象的构造函数的原型对象 (对象){constructor: ƒ Person(name)}
Person.prototype.__proto__
原型对象的原型 类似(指针) {...__proto__: null...}
Object.prototype
对象的原型对象 (对象) {...__proto__: null...}
Object.prototype.__proto__
对象的原型对象的原型 null
null.prototype
null的原型对象 // 报错 null没有原型,查找原型链结束
PS:
__ proto__
是一个访问器或索引,用其找到构造函数的prototype
prototype
是一个构造器,里面包含了构造函数里的各种属性,方法例子:
function Person(name) {
this.name = name
}
var p = new Person('ycl');
console.log(p.__proto__) // Person.protptype (Object)-- 实例对象的原型 就是 实例对象构造函数的原型对象
console.log(p.__proto__.__proto__) // Object.prototype
console.log(p.__proto__.__proto__.__proto__) // null -- Object原型对象没有原型了(找到头了)
console.log(p.__proto__.__proto__.__proto__.__proto__) // err报错 -- null是基础数据类型,没有原型
console.log(p.constructor) // Person -- 实例化对象的构造函数
console.log(p.prototype) // undefined -- 实例没有prototype属性
console.log(Person.constructor) // Function 一个空函数
console.log(Person.prototype) // 打印出Person.prototype这个对象里所有的方法和属性
console.log(Person.prototype.constructor) // Person
console.log(Person.prototype.__proto__) // Object.prototype
console.log(Person.__proto__) // Function.prototype
console.log(Function.prototype.__proto__) // Object.prototype
console.log(Function.__proto__) // Function.prototype
console.log(Object.__proto__) // Function.prototype
console.log(Object.prototype.__proto__) // null
改变this指向的。(还有箭头函数)
如果函数处于非严格模式下,则this指定为
null
或undefined
时会指向全局对象window
函数名.call(要改变的 this 指向,要给函数传递的参数1,要给函数传递的参数2, ...)
函数名.apply(要改变的 this 指向,[要给函数传递的参数1, 要给函数传递的参数2, ...])
var newFn = 函数名.bind(要改变的 this 指向,要给函数传递的参数1,要给函数传递的参数2, ...)
直接写多个参数
newFn(要给函数传递的参数n)
如果参数多余,则不生效(可以在原函数和新函数两个位置传参,优先考虑的是binf内部的参数)不会立即执行函数,而是返回一个已经改变了 this 指向的函数
值数据类型(基本数据类型):存放在栈(stack)内存中的简单数据段,变量直接存储数据
Number
隐式的编码为浮点类型String
Boolean
Undefined
null
Symbol
(ES6新增)唯一并且不可变的原始值并且可以用来作为对象属性的键BigInt
可以表示任意大小的整数,存储和操作巨大的整数,甚至超过 Number 的安全整数限制引用数据类型(复杂数据类型):存放在堆(heap)内存中的对象,栈内存中的变量存放的是堆内存中具体内容的引用地址
Object
(统称)
Object
、Array
、function
、Date
、RegExp
…typeof()
查看字面量或者变量的数据类型
.constructor
判断构造函数
注意:undefined和null没有contructor属性
console.log(false.constructor === Boolean);// true
instanceof
判断一个对象的构造函数是否等于给定的值(一般用于判断自定义构造函数实例。)
({}) instanceof Object // true
[] instanceof Array // true
new Date() instanceof Date // true
/123/g instanceof RegExp // true
Object.prototype.toString.call()
Object.prototype.toString.call(1); '[object Number]'
Object.prototype.toString.call('1'); '[object String]'
isArray()
isNaA()
事件循环eventLoop是js引擎执行js代码的机制,用来实现js的异步特性。
步骤:
- 执行一个宏任务。
- 执行微任务,直到微任务队列为空。
- 循环1、2。
宏任务:
script整体代码
、setTimeout
、setInterval
、requestAnimationFrame
、I/O
微任务:
Promise.then
、Promise.catch
、nextTick
防抖(输入框):
节流(验证码):
深拷贝:
- 新对象的属性与源对象的属性不共享相同的引用(指向相同的底层值)的副本。
- 当更改源或副本时,一定不会导致其他对象也发生更改。
浅拷贝:
- 新对象的属性与源对象的属性共享相同的引用(指向相同的底层值)的副本。
- 当更改源或副本时,可能导致其他对象也发生更改。
拷贝的划分都是针对引用类型来讨论的
基础数据类型拷贝:栈中变量存储的是值本省,拷贝会开辟新的内存空间,所以一定是深拷贝
引用数据类型拷贝:栈中变量存储的是堆内存中真正数据内容的引用,所以有深浅拷贝之分
深拷贝:
JSON.parse(JSON.stringify(能被序列化的JS对象))
– 先将对象转为JSON字符串,再转回(全新的)JS对象 – 注意有bug
封装递归函数cloneDeep()
function deepClone (obj) {
// 如果值 值类型 或 null ,直接返回
if (typeof obj !== 'object' || obj === null) {
return obj;
}
let copy = {};
// 如果对象是数组
if (obj.constructor === Array) {
copy = [];
}
// 遍历对象的每个属性
for (let k in obj) {
// 如果 key 是对象的自有属性
if (obj.hasOwnProperty(k)) {
copy[k] = deepClone(obj[k]); // 递归调用 deepClone
}
}
return copy;
}
浅拷贝
for循环
Object.assign()
将所有可枚举的自有属性从一个或多个源对象复制到目标对象,返回修改后的对象。拷贝的是(可枚举)属性值。假如源值是一个对象的引用,它仅仅会复制其引用值
Array.prototype.concat()
合并两个或多个数组, concat方法会返回一个新数组
跨域是什么
解决跨域的方案
JSONP
标签的引入没有跨域限制(JSONP原理)get
请求。var script = document.createElement('script');
script.type = 'text/javascript';
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
document.head.appendChild(script);
// 回调执行函数
function handleCallback(res) {
alert(JSON.stringify(res));
}
handleCallback({"success": true, "user": "admin"}) // 服务端返回
CORS(跨域资源共享)
nginx代理
外部引入CSS有2种方式:@import、link
从属关系区别
link
是html标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等。(加载任意文件,如图标)@import
是 CSS 提供的语法规则,只有导入样式表的作用(在css文件中使用)。(只能加载样式)加载顺序区别
link标签
引入的 CSS 在页面加载时被同时加载(异步加载)@import
引入的 CSS 在页面加载完毕后被加载(同步加载)权重区别
link
方式的样式的权重高于@import
DOM可控性
link标签
支持使用javascript改变样式
@import
不支持
三者共同点,都是相对于某个基点的定位,不同之处仅仅在于基点不同
fixed 窗口定位
top
、bottom
、left
、right
这四个属性一起使用relative 相对定位
static
定位时的位置top
、bottom
、left
、right
这四个属性一起使用,用来指定偏移的方向和距离。absolute 绝对定位
static
定位,否则定位基点就会变成整个网页的根元素html
top
、bottom
、left
、right
这四个属性一起使用,用来指定偏移的方向和距离。一、存储时效不同
二、存储的大小不同
三、与服务端通信
1.cookie可以和服务端进行通信 一般请求头 存储关键信息
2.localStorage、sessionStorage 只能前端存储
四、读写的便捷度
1.localStorage、sessionStorage 操作更简单
五、支持的浏览器
1.cookie 出现比较早 支持所有的浏览器
2.localStorage、sessionStorage 不支持低版本的ie IE8版本之下的都不支持
animation 指定一组或多组动画(执行动画)
transition 为一个元素在不同状态之间切换的时候定义不同的过渡效果(过渡动画)
transform 旋转,缩放,倾斜或平移给定元素(位移)
@keyframe 通过在动画序列中定义关键帧的样式来控制 CSS 动画序列中的中间步骤(自定义动画)
set
const res = Array.from(new Set(arr))
// Array.from() :对一个类似数组或可迭代对象创建一个新的浅拷贝的数组实例。
weakset
// WeakSet 结构与 Set 类似,也是不重复的值的集合,只有三个方法,没有属性
// WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
// WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
// WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中。
数组循环方法
let len = arr.length
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1)
len-- // 减少循环次数提高性能
j-- // 保证j的值自加后不变
}
}
}
filter、indexOf
// filter不会改变原有数组的值,产生一个新的数组
arr = arr.filter((item, index) => {
return arr.indexOf(item) === index
})
includes
// includes判断字符串或者数组里是否包含这一项,如果包含 返回true 反之 返回false
const newArr = []
arr.forEach(item => {
if (!newArr.includes(item)) {
newArr.push(item)
}
})
Map
const map = new Map()
const newArr = []
arr.forEach(item => {
if (!map.has(item)) { // has()用于判断map是否包为item的属性值
map.set(item, true) // 使用set()将item设置到map中,并设置其属性值为true
newArr.push(item)
}
})
盒子变化会重排、任意样式会引起重绘、回流就是重排重绘
重绘不一定导致重排,重排一定导致重绘
几何属性
(位置、尺寸)将会重新计算style,并且需要更新布局树,然后重绘非几何属性
(元素的背景颜色),则只会重绘不会重排提出Promise的原因
三种状态的转换(只可能有两种情况)
pending
(进行中)resolve
函数,状态变为 fulfilled
(已成功)reject
函数,状态变为 rejected
(已失败)then、catch和finally
接收成功时的结果 .then(回调函数)
接受失败时的结果.catch(回调函数)
无论成功与否都会调用.finally(回调函数)
Promise.all()
Promise.race()
声明
var
允许重复声明let
和 const
不允许重复声明变量赋值
let
与var
声明的时候可以不赋值,const
声明的时候必须赋值let
与var
声明的变量的值可以改变,const
声明的变量的值不可以改变预解析
let
和 const
声明的变量不会在预解析的时候解析(也就是没有变量提升)作用范围
var
在函数内部声明,作用域为函数范围;在函数外部声明,作用域为全局范围let
和 const
声明的变量会被所有代码块限制作用范围(块范围) 减少事件数量、预测未来元素、避免内存外泄
ul
上绑定会比在li
绑定上少很多事件,少花费更多内存li
上,则对列表项的增删都将导致元素需要新绑定或解绑事件const obj = new Object();
const obj = {};
function createPerson(name){
var a =new Object(); // 创建一个新的对象
a.name = name; // 向对象中添加属性
return a;
}
var obj = createPerson("羊羊");
function Test() {} // Test被称为“类”或者“构造函数”。Test是t的构造函数。
const obj = new Test();
function Person(name){
this.name = name; //属性
if (typeof this.sayName != "function"){
Person.prototype.sayName = function(){
alert(this.name);
};
}
}
var friend = new Person("羊羊");
friend.sayName();
虚拟节点Vnode的本质就是用树型结构的JS普通对象来描述真实dom结构的信息。
防抖机制、合并渲染
如何创建虚拟Dom?
render()
– 创建组件虚拟 DOM 树
h()
– 创建虚拟 DOM 节点 (vnode)
VNode
决定如何渲染?
虚拟Dom的好处?
成本低——运用防抖机制进行合并渲染
vnode
中修改,再diff,最后对dom tree
进行一次集中修改,减少游览器的重绘及回流同时使用
v-if
和v-for
是不推荐的,因为这样二者的优先级不明显
Vue2,在一个元素上同时使用 v-if
和 v-for
时,优先级v-for
>v-if
Vue3,优先级v-if
>v-for
。
这意味着 v-if
的条件将无法访问到 v-for
作用域内定义的变量别名:
- {{ it.name }}
可以外面套一层,
v-for
移上去
query、查询参数、params、动态路由、meta
query
查询参数
this.$router.push({
path: '/detail',
query: {
id: id
}
})
params
this.$router.push({
name: 'Detail',
params: {
id: id
}
})
动态路由
{ path: '/:articleName', component: Article }
meta
{ path: '/home', component: Home, meta: { reqquireLogin: true } }
在创建路由器实例时,
history
配置允许我们在不同的历史模式中进行选择。
routerview
组件 – 路由渲染
createWebHashHistory
创建
createWebHistory()
创建
父组件传参给子组件
v-bind
进行数据传递(属性下发),子组件在props
中接收属性父组件调用子组件方法
子组件修改父组件参数
方法一
@event="$emit(父组件的自定义事件,参数...)"
发送给父组件@父组件的自定义事件="处理器"
触发处理器来进行相关操作方法二
@event="$parent.处理器(参数)"
直接将数据传给父组件的处理器进行相关处理vuex全局数据共享
provide和inject来实现全局状态管理
v-if
条件渲染v-show
伪条件渲染
display
实现的state
存放状态。
getters
state的计算属性,对数据进行过滤后暴露
mutations
赋值数据更新,同步操作
actions
提交mutayion,异步操作。
modules
将store模块化
state
、getters
、mutations
、actions
,甚至是嵌套子模块getter
、action
及 mutation
都会自动根据模块注册的路径调整命名全局数据共享
数据流向是单向的(state是唯一数据源、单一状态数)
可以严格控制数据流,还可以实现数据的可预测化
vue中,如果data不是一个工厂函数,或者函数中不是返回一个对象字面量,那么实例化多个组件(组件复用)的时候,不同组件间会共享同一个引用数据data,data的改变会影响到每个实例,这时不符合预期的。
在组件的style标签中加了scoped属性,则会在所有选择器上添加对应的属性选择器来只对自身组件产生影响,以此来实现样式隔离
对每个组件中的DOM元素添加格式为:data-v-[hash:8]的属性
<p data-v-37b1dc3d>Hello World!p>
然后该组件的所有选择器也会添加上对应的**[data-v-[hash:8]]**属性选择器来只对自身组件产生影响。以此来实现样式隔离。
p[data-v-37b1dc3d]{
color:red;
}
在某些场景中,需要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段
插槽内容与出口
渲染作用域
Vue 模板中的表达式只能访问其定义时所处的作用域。
父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域。
默认内容
默认内容...
具名插槽
当一个组件中包含多个插槽出口时,需要用到具名插槽
name
的插槽被称为具名插槽。
name
的
出口会隐式地命名为default
。
name
name
给插槽分配唯一的 ID,以确定每一处要渲染的内容。v-slot
指令的
元素,并将目标插槽的名字传给该指令插槽内容...
,简写为插槽内容...
节点都被隐式地视为默认插槽的内容。动态插槽名
动态指令参数在 v-slot
上也是有效的
...
作用域插槽
默认作用域插槽
当同时使用父组件域内和子组件域内的数据,可以向一个插槽的出口上传递 attributes:
槽接收proprs
{{ slotProps.text }} {{ slotProps.count }}
具名作用域插槽
当同时使用父组件域内和子组件域内的数据,可以向一个插槽的出口上传递 attributes:
插槽 props 可以作为 v-slot
指令的值被访问到:v-slot:name="slotProps"
{{ headerProps }}
{{ defaultProps }}
{{ footerProps }}
headerProps
的结果是 { message: 'hello' }
可以使用keep-alive
这个组件和动态组件配合实现保留组件状态,避免重新渲染(内存不释放组件,切换组件输入框内容不消失)
<keep-alive>
<component :page-name="pageName" :is="pageName">component>
keep-alive>
针对keep-alive
这个组件提供了两个生命周期钩子函数
activated
:进入页面deactivated
:离开页面原生JS获取DOM节点
document.querySelector(选择器
)
document.getElementById(id选择器)
document.getElementsByClassName(class选择器)
ref属性、$refs 获取元素或组件实例的对象(响应式)
特殊属性ref
用于注册模板引用。
<p ref="p">hellop>
组件实例$refs
一个包含 DOM 元素和组件实例的对象,用于访问模板引用
// 选项式
```
因为每个 vue 的组件实例上,都包含一个 $refs 对象,里面存储着对应的DOM元素或组件的引用。
ref钩子函数 创建任何类型的ref(响应式)
eg
// 组合式
<script>
export default {
setup() {
const input = ref(null)
// ...
return {
input
}
}
}
</script>
// 组合式(setup语法糖)
<script setup>
import { ref, onMounted } from 'vue'
// 声明一个 ref 来存放该元素的引用
// 必须和模板里的 ref 同名
const input = ref(null)
onMounted(() => {
input.value.focus()
})
</script>
组件实例 $parent
this.$parent.属性
v-model是一个数据双向绑定的指令——语法糖
在input事件上使用v-model
,等价于用value传值
v-bind 绑定一个value属性
v-on 指令给当前元素绑定input事件
<input v-model="searchText" />
<input
:value="searchText"
@input="searchText = $event.target.value"
/>
在组件上使用v-model
将内部原生 元素的
value
属性绑定到 modelValue
属性上
当原生的 input
事件触发时,触发一个携带了新值的 update:modelValue
自定义事件
在父组件内给子组件标签添加 v-model ,其实就是给子组件绑定了 value 属性
子组件内使用 prop 创建 创建 value 属性可以拿到父组件传递下来的值,名字必须是 value
子组件内部更改 value 的时候,必须通过 $emit 派发一个 input 事件,并携最新的值
v-model 会自动监听 input 事件,把接收到的最新的值同步赋值到 v-model 绑定的变量上
<CustomInput v-model="searchText" />
<CustomInput
:modelValue="searchText"
@update:modelValue="newValue => searchText = newValue"
/>
setter、getter、观察模式、发布订阅模式
防抖机制、提高渲染性能
Vue可以响应数据变化,数据变化后会自动更新视图,如果每次修改都触发视图更新,会导致多次重复和不必要的渲染操作,例如一个组件使用了两个data的属性,更新两个属性如果触发两次渲染的话,会影响性能。因此Vue采取异步更新。
在创建路由器实例时,
history
配置允许我们在不同的历史模式中进行选择。
routerview
组件 – 路由渲染
createWebHashHistory
创建
createWebHistory()
创建
组件注册方法
全局注册(component方法)
const app = Vue.createApp(options)
app.component('my-panel', MyPanel)
app.mount('#root')
局部注册(components属性)
Vue.createApp({
components: {
'my-panel': MyPanel
}
}).mount('#root')
异步组件定义(路由组件懒加载)
import()
const List= () => import("@/components/List");
defineAsyncComponent()
– 定义一个异步组件,它在运行时是懒加载的。
import { defineAsyncComponent } from 'vue'
const XXX = defineAsyncComponent(() => {
// 返回Promise...
// 导入组件...
})
动态组件
,通过:is
属性控制模板的样式,传给:is
的值可能为:
来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过
组件强制被切换掉的组件仍然保持“存活”的状态。key是循环渲染中,作为虚拟dom对比的标志,所以可以提高diff算法性能
props
生命周期就是在组件的不同时期实现不同业务
beforeCreate()
created()
表示vue组件实例对象构造完成,数据已经绑定到vm层
PS:Vue中,没有具体元素,只有虚拟Dom
<h3 ref="node">hello worldh3>
// Vue实例
// this.$refs.node
数据已经完成了初始化,但是节点没有完成实例挂载,所以不会触发
如果created中存在异步赋值,那么会导致二次渲染,原因:所有生命周期都是同步代码,所以异步执行不会得到等待
综上:created非异步赋值不会导致二次渲染,而mounted一定会导致二次渲染
挂载阶段
beforeMount()
mounted()
注意:这里不能写this,因为这里绑定的代码会重新编译修改阶段
beforeUpdate()
updated()
销毁阶段(v2 destroy) / 卸载阶段(v3 unmount)
beforeDestory()
destroyed()
unmount()
beforeUnmount()
组件类继承、单一继承、属性合并、多组件合并
mixins可以接收一个混入对象的数组(组件类继承),可以混入多个mixin来多组件合并,进行属性合并
extends接收的是对象或函数(单一继承),只能继承一个
全局组件通信 : 信两个任意的组件,不管是否有关联( 父子、爷孙, 子子)的组件,都可以直接进行交流通信
EventBus
- vue2$root
$on
$emit
mitt
- vue3globalProperties
getCurrentInstance
ctx
代替this性能优化
page
、size
@import
引入,会造成额外的i请求async
、defer
、放到body底部
、动态创建script标签
…)
引入文件为同步加载,可能导致主线程被阻塞
(不管怎样,这个文件都会在页面初始化时加载,想要不使用文件,文件就不加载?)
使用第三方库 requirejs 或 seajs 都为按需加载
原理同 ()=>import (path)
一般老项目jquery
如何异步加载JavaScript文件?
使js延迟加载,页面加载完了(onload之后)再加载文件
声明为异步加载如何实现按需加载?
requirejs
seajs
import()
箭头函数只能简写函数表达式,不能简写声明式函数
箭头函数内部没有 this,箭头函数的 this 是上下文的 this
箭头函数内部没有 arguments
这个参数集合
函数体只有一行代码的时候,可以不写 {}
,并且会自动 return
变量提升的理解
var
会存在变量提升;而let和const不会提升var 和 function提升有什么区别
变量提升var
function test1(){
console.log(a)
var a = 10
}
// 等同于
function test1(){
var a;
console.log(a); // undefined
a = 10;
}
函数提升function
function test2(){
console.log(a)
function a(){}
}
// 等同于
function test2(){
function a(){}
console.log(a) // f a(){}
}
注意:var xx = fn()
只有变量定义的提升,函数未运行则不会提升
function test3(){
console.log(a)
var a = function(){}
}
// 等同于
function tests(){
var a;
console.log(a); // undefined
a = function(){}
}
原型继承 – 子类.prototype = new 父类构造函数()
根据js原型链特性,在访问对象属性时候,如果对象私有属性中没有该属性,会去对象的构造函数的prototype中查找。可以将子类构造函数的prototype赋值为父类的实例,这样在子类对象中查找属性找不到时候,就可以在父类实例中找到,从而让子类可以使用父类的属性。
构造函数继承 – 父类.call(this, 参数);
为了解决原型继承不能传参和不能继承私有属性的缺点,可以使用借用构造函数继承。
在子类构造函数中使用call/apply调用父类构造函数,将父类构造函数指向子类实例。
**组合继承 **-- 同时使用 原型继承 和 构造函数继承
让子类即继承了父类的原型属性也继承了父类的私有属性,需要注意的是,父类的property属性既存在于子类的私有属性中,也存在于子类的原型属性中,这导致了不必要的重复。
extends class 子类 extends 父类{}
流程:遇到script标签,停止解析HTML,等待外链CSS加载并解析完成、内联CSS解析完成后,再执行JavaScript。执行完JavaScript再开始解析HTML。
js延迟加载:js下载和执行时候不会停止解析HTML
defer
async
声明为异步加载
动态创建dom(script标签)
jQuery的getScript()
setTimeout
js外部引入的文件放到页面底部,来让js最后引入
全局变量、闭包、dom删除或清空、事件未清除、元素引用
全局变量
使用闭包但
全局变量
闭包
dom删除或清空
<div id="root">
<ul id="ul">
<li>li>
<li id="li">li>
<li>li>
ul>
div>
<script>
let root = document.querySelector('#root')
let ul = document.querySelector('#ul')
let li = document.querySelector('#li')
root.removeChild(ul) // 由于ul变量存在,整个ul及其子元素都不能GC(垃圾回收)
ul = null // 虽置空了ul变量,但由于li变量引用ul的子节点,所以ul元素依然不能被GC
li = null // 已无变量引用,此时可以GC
script>
事件未清除
setTimeInterval()
与setTimeOut()
clearInterval()
与clearTimeOut()
requestAnimationFrame()
cancelAnimationFrame()
元素引用
对象的强引用:将一个引用对象通过变量或常量保存时,那么这个变量或常量就是强引用,这个对象就不会被回收
Map、Set强引用
let obj = {id: 1} // 引用对象
let user = {info: obj}
let set = new Set([obj])
let map = new Map([[obj, 'hahaha']])
// 重写obj
obj = null
//以下强引用,并不会因为垃圾回收掉
console.log(user.info) // {id: 1}
console.log(set)
console.log(map)
map.delete(obj);
obj = null; //此时才能去除map对key所引用对象的强引用
let weakSet = new WeakSet([obj])
let weakMap = new WeakMap([[obj, 'hahaha']])
// 重写obj引用
obj = null
// {id: 1} 将在下一次 GC 中从内存中删除
GC(垃圾回收机制):查找垃圾释放空间、回收空间
标记清除
引用计数
核心思想
优点:
缺点:
js 为单线程,从上至下依次执行;事件轮询是用来实现异步的
setTimeout
、setInterval
、、Promise
、process.nextTick
、requestAnimationFrame
Array.prototype.XX()
切割/拼接(可能会修改原数组)
slice(begin,end)
切片
splice(start,deleteCount,item...)
拼接
join(separator)
拼接
concat(array2...)
合并
增删元素(均会修改原数组)
unshift(elment0,...)
头部添加
shift()
头部删除
pop()
尾部删除
push()
尾部添加
遍历(均不会修改原数组)
some(callbackFn)
是否存在
every(callbackFn)
是否所有
filter(callbackFn)
过滤
map(callbackFn)
映射
forEach(callbackFn)
遍历
reduce(reducer(previousValue,currentValue,currentIndex,array),initialValue)
累积
reducer
回调函数遍历数组后的结果添加请求参数、改变请求地址
客户端发送 GET 请求且请求资源成功,但请求的资源(自上次访问以来或者根据请求的条件)未被修改,则
客户端使用的是本地游览器缓存,而不从服务器下载。
游览器缓存分为强制缓存和协商缓存,强制缓存不需要向服务器发送请求,协商缓存则需要发送请求,通过304 code判断是否需要使用缓存
git clone [url]
克隆一个远程仓库git pull
从远程仓库拉取代码到工作空间git add [file-name1] [file-name2] ...
从工作区添加指定文件到暂存区git commit -m [massage]
将暂存区所有文件添加到本地仓库git push
将文件添加到远程仓库git log
显示所有commit日志git branch
查看当前分支git checkout -b [file-name]
创建并切换分支git status [file-name]
查看指定文件状态text-align: center;
position: absolute;
)
width: 100px;
、margin: 0 auto;
行内元素
line-height: 100px;
、height: 100px;
块级元素
设置父元素为弹性盒子 display: flex;
已知高度
top: calc(50% - width/2);
、``未知高度
margin-top: 50%;
、translate: -50%;
或 transform: translateX(2em);
根字体、父元素字体、绝对像素、视窗高度、父元素百分比
px
em
rem
rpx
vh、vw
%
dispaly:none;
设置元素不可见(元素不会占用任何空间)(删除dom)visibility:hidden;
设置元素不可见(但是依旧占据页面空间,会影响布局)opacity:0;
设置元素透明度width:0;
height:0
宽高为0clip-path:polygon(0px 0px,0px 0px,0px 0px,0px 0px);
left:-9999px
或 transform:translateX(-9999px);
将元素移出窗口浮动的元素会造成父元素高度塌陷,因此需要清除浮动。
在浮动元素后增加一个挡板元素,设置clear: both;
设置clear的元素不受前面浮动元素影响,位置会放在浮动元素后面,因此可以把父元素撑开。
// 父元素高度塌陷,需要清除浮动
内容1 // 浮动
内容2 // 浮动
挡板元素 // 挡板,样式设置clear: both;
父元素设置after伪元素,设置clear: both;
.father::after{
content: "";
height: 0;
display: block;
clear: both;
zoom: 1;
}
父元素设置overflow: hidden。
搜索引擎优化 (SEO,Search Engine Optimization)
利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名
语义化html标签
、
、
、
、
…添加meta
description 网站相关描述
<meta name="keywords" content="技术交流 技术博客交流">meta>
keywords 关键字(谷歌已不使用其作为网站排名因素)
<meta name="description" content="一个有爱的技术交流社区 csdn 欢迎您的到来 ">meta>
title 页面标题
少用iframe
图片加上alt
npm
cnpm
yarn
pnpm
vue、react、angular
构建工具:ES6\ES7游览器不认识就用构造工具将其编译成游览器认识的
实现代码压缩:空格、换行、注释等
通过命令直接构建一个应用,包含路由、状态管理器、拦截等,也会有一些页面(登录页面、首页、看板、列表、表单等)
encodeURIComponent()
把字符串作为 URL 组件的一部分(如path/query/fragment等)进行编码decodeURI()/decodeURIComponent()
解码URL中被转义的字符自适应和响应式区别
自适应包含响应式
响应式:根据 变化样式
为了适应所有设备的观看效果
自适应:不同平台加载不同样式
根据不同的用户去匹配,需要做多版本,