每个对象都会在其内部初始化一个属性,就是prototype(原型)。
当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去,也就是我们平时所说的原型链的概念。
this总是指向函数的直接调用者;
如果有new关键字,this指向new出来的那个对象;
this的指向问题:
1.作为对象的属性被调用,this指向该对象
2.作为普通函数得调用,this总是指向全局对象(通常为window),严格模式下this指向undefined
3.作为构造器调用,通常情况下this指向被构造函数返回的实例,例外如果构造函数显式的返回一个Object类型的对象,name结构也是只会得到这个对象
4.call和apply调用
动态改变this指向,使用一个指定的this值和单独给出的一个或多个参数来调用一个函数
允许为不同的对象分配和调用属于一个对象的函数/方法
call()方法:指定的this + 多个参数
apply()方法:指定的this + 一个包含多个参数的数组
5.箭头函数,箭头函数不会创建自己的this,它会从自己的作用域的上一层继承this
null 表示一个对象是“没有值”的值,也就是值为“空”;undefined 表示一个变量声明了没有初始化(赋值);
undefined不是一个有效的JSON,而null是;
undefined的类型(typeof)是undefined;null的类型(typeof)是object;
深拷贝和浅拷贝是只针对引用数据类型,例如:Object和Array;
浅拷贝只复制指向某个对象的指针而不复制对象本身,新旧对象还是共享同一块内存;
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象;
深拷贝方法:
1.JSON.parse(JSON.stringify(obj))
原理: 用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
2.递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝
闭包就是能够读取其他函数内部变量的函数,在本质上是函数内部和函数外部链接的桥梁
// 经典问题
var arr = []
for(var i = 0; i < 10; i++){
arr[i] = function () {
console.log(i)
}
}
arr[0](); // 10
arr[1](); // 10
arr[2](); // 10
// 利用闭包来解决
var arr = []
for(var i = 0; i < 10; i++){
arr[i] = (function (i) {
return function () {
console.log(i);
}
})(i)
}
arr[0](); // 0
arr[1](); // 1
arr[2](); // 2
闭包处理的还是作用域的问题,解决该问题的方法还可以是利用ES6语法,var声明改成let声明
分成:结构层、表示层、行为层
结构层:由 HTML 或 XHTML之类的标记语言负责创建。标签,也就是那些出现在尖括号里的单词,对网页内容的语义含义做出了描述,但这些标签不包含任何关于如何显示有关内容的信息。例如,P标签表达了这样一种语义:“这是一个文本段。”
表示层:由 CSS 负责创建。 CSS对“如何显示有关内容”的问题做出了回答。
行为层:负责回答“内容应该如何对事件做出反应”这一问题。这是 Javascript 语言和 DOM主宰的领域。
TCP协议在传输层,IP协议在网络层,HTTP协议在应用层。
1.服务器角度
采取CDN加速,开启gzip压缩,允许使用强缓存或协商缓存,增加服务器带宽
2.客户端角度
合理组织CSS、JavaScript代码位置,减少DOM操作、添加事件委托,部分操作可设置防抖和节流,对于可预见的操作采取preload或prerender的预加载,对于图片可以懒加载,合并CSS图片(精灵图/雪碧图),减少使用iframe,资源优化打包角度
3.资源优化打包角度
使用打包工具将Js文件、CSS文件和静态文件进行恰当打包处理。
跨域问题来自于浏览器的同源策略,即当协议、域名、端口号任意一个不同时,都会引发跨域问题。
解决方法:jsonp、CORS
宏任务是由宿主发起的(Node、浏览器),而微任务由JavaScript自身发起(JS引擎)。
宏任务(macrotask) | 微任务(microtask) | |
---|---|---|
发起者 | Node、浏览器 | JS引擎 |
具体事件 | 1. script (可以理解为外层同步代码) 2. setTimeout/setInterval 3. UI rendering/UI事件 4. postMessage,MessageChannel 5. setImmediate,I/O(Node.js) | 1. Promise 2. MutaionObserver 3. Object.observe(已废弃; Proxy 对象替代)4. process.nextTick(Node.js) |
运行顺序 | 后运行 | 先运行 |
触发新一轮Tick | 会 | 不会 |
其中比较注意的是promise的内部既包含宏任务也包含微任务,promise内部执行为宏任务,then执行为微任务
1.语义标签
例如:<header>定义文档头部、<footer>定义文档尾部、<nav>定义文档的导航、<section>定义文档中的节
2.增强型表单
例如:<search>用于搜索、<tel>定义输入电话号码和字段、<date>选取日期
3.新增表单属性
例如:placehoder输入框默认提示文字、autofocus规定在页面加载时,域自动获得焦点、required要求输入的内容是否可为空
4.音频<audio src=" ">audio>、视频<video src=" ">video>
5.canvas绘图和SVG
Web Worker的作用就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。
Worker线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。
href 是指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,用于超链接。
src是指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;在请求src资源时会将其指向的资源下载并应用到文档内,例如js脚本,img图片和frame等元素。
border-radius:实现倒角、圆角
box-shadow:阴影
text-shadow:字体阴影
gradient:渐变
transform:rotate scale skew translate 旋转 缩放 定位 倾斜
animation:动画
等等
1.id选择器 #id
2.类选择器 .class
3.标签选择器 div
4.相邻选择器 div+p
5.子选择器 div>p
6.后代选择器 div p
7.属性选择器 div[class="main"]
8.伪类选择器 div::hover
有两种模型:IE盒子模型、标准盒子模型
IE盒子模型:content部分包含border和padding
标准盒子模型:内容(content)、填充(padding)、边界(margin)、边框(border)
在IE盒子模型中,width 和 height 指的是内容区域+border+padding的宽度和高度。
在标准盒子模型中,width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸
CSS3中的box-sizing属性:
box-sizing:border-box表示盒模型基于IE的盒模型,width和height决定盒模型的content区、padding区和border区。
box-sizing:content-box表示盒模型基于标准盒模型,width和height只决定盒模型的content区
box-sizing:inherit表示继承自父元素。
/*已知容器的宽高 设置层的外边距*/
div {
position: relative; /* 相对定位或绝对定位均可 */
width:500px;
height:300px;
top: 50%;
left: 50%;
margin: -150px 0 0 -250px; /* 外边距为自身宽高的一半 */
}
/*不知宽高-水平垂直居中 利用 `transform` 属性*/
div {
position: absolute; /* 相对定位或绝对定位均可 */
width:500px;
height:300px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/*利用flex布局*/
div {
display: flex;
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
}
/*让绝对定位的div居中*/
div {
position: absolute;
width: 300px;
height: 300px;
margin: auto;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
beforeCreate( 创建前 ) => created(创建后)=> beforeMount(挂在前)=> mounted(挂载后)=>
beforeUpdate(数据更新前调用)=> updated(更新后)=> beforeDestroy(实例销毁前)=> destroyed(实例销毁后)
activated(被 keep-alive 缓存的组件激活时调用)
decactived(被 keep-alive 缓存的组件停用时调用)
实现mvvm的双向绑定,是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调
1.加载过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
2.子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
3.父组件更新过程
父beforeUpdate->父updated
4.销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
1.props 和 $emit
父组间通过props向下传递数据给子组件,子组件通过event给父组件发送消息,实际上就是子组件把自己的数据发送给父组件。
2.$attrs 和 $listeners
祖孙间隔代通过$attrs传递数据,$listeners监听数据的改变
<template>
<div>
<B :messageb="messageb" :messagec="messagec" @getC="getC" @getB="getB" />
div>
template>
<script>
export default {
name: 'A',
data(){
return {
messageb:'b', //传递给B的数据
messagec:'c' //传递给C组件的数据
}
},
methods:{
//执行B子组件触发的事件
getB(val){
console.log('B组件的数据:'+ val) //打印 ‘B组件的数据:b’
},
//执行C子组件触发的事件
getC(val){
console.log("C组件的数据:" + val) //打印 'C组件的数据:c'
}
}
}
script>
<template>
<div>
<input type="text" v-model="mymessage" @change="chnageHandle()" />
<C v-bind="$attrs" v-on="$listeners" />
div>
template>
<script>
export default {
name: 'B',
props:[
messageb:{ // 获得A组件传递过来的数据:'b'
type: String,
default: ''
}
],
methods:{
chnageHandle(){
//触发A组件中的事件,把messageb给A组件
this.$emit('getB',this.messageb)
}
}
}
script>
<template>
<div>
<input type="text" v-model="$attrs.messagec" @change="changeHandle()">
div>
template>
<script>
export default {
name: 'C',
data () {
return {}
},
methods:{
changeHandle(){
//触发A组件中的事件,把从A得到的数据c还给A组件
this.$emit('getC',this.$attrs.messagec)
}
}
}
script>
3.provide和 inject
provide 和 inject成对出现,用于父级组件向下传递数据;
父组件中通过provide来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provide中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。
<template>
<div>
<son>son>
div>
template>
<script>
export default {
name: 'grandparent',
provide: {
giveSonMessage:'给子组件的数据',
giveGrandsonMessage:'给孙组件的数据'
},
data(){
return {}
}
}
script>
<template>
<div>
<input type="text" v-model="value">
<grandson>grandson>
div>
template>
<script>
export default {
name: 'son',
inject:['giveSonMessage'], //得到父组件传递过来的数据
data(){
return {
value:this.giveSonMessage
}
}
}
script>
<template>
<div>
<input type="text" v-model="value">
div>
template>
<script>
export default {
name: 'grandson',
inject:['giveGrandsonMessage','giveSonMessage'], //得到爷组件传递过来的数据,也能获得爷给父的数据
data(){
return {
value:this.giveGrandsonMessage
}
}
}
script>
4.vuex处理组件之间的数据交互
如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的