学习新知识确实累,起码比写代码累一些,还要温故而知新,不知道我定不定得住
js事件流之事件捕获和事件冒泡
事件捕获
事件捕获的思想就是从不太具体的dom结点先开始接收事件,而最具体的dom结点最后接收事件,也就是事件从父元素到子元素传播。从外到内,实现事件捕获
事件冒泡
事件冒泡的思想是从最具体的dom结点开始接收事件,逐级向上传播
阻止冒泡
e.stopPropagation
示例代码:
const btn = document.getELmentById('btn');
btn.onclick = function(e){
e.stopPrapagation()
}
事件委托
- 事件委托本质上是利用了浏览器事件冒泡的机制。因为事件在冒泡过程中会上传到父节点,并且父节点可以通过事件对象获取到目标节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件代理。
new
通过new创建的对象,可以访问到构造函数的原型对象,通过new操作符,实例对象与构造函数通过原型链连接起来。
构造函数返回值问题
-
如果构造函数中,用return返回一个原始类型的数据,那么这个数据毫无意义
function Test(name) { this.name = name return 1 } const t = new Test('zdk') console.log(t.name) // 'zdk' 接收不到return返回的1 -
如果返回的是对象,return正常工作
手动实现new操作符
function create(Con, ...args) {
let obj = {}
Object.setPrototypeOf(obj, Con.prototype)
let result = Con.apply(obj, args)
return result instanceof Object ? result : obj
}
new一个对象的过程
在内存中创建一个新对象。
- 这个新对象内部的
[[Prototype]]特性被赋值为构造函数的prototype属性。 - 构造函数内部的
this被赋值为这个新对象(即this指向新对象)。 - 执行构造函数内部的代码(给新对象添加属性)。
- 如果构造函数返回对象,则返回该对象;否则,返回刚创建的新对象(空对象)。
有关var,let和const
var的缺陷:
-
全局变量挂载到全局对象,全局对象成员污染问题(gobal,windows)
-
允许重复的变量声明,导致数据被覆盖
var a = 1 var a = 2 console.log(a) // a=2 -
变量提升:怪异的数据访问,没有块级作用域,只能用闭包来解决
let:
-
let声明的变量不会挂载到全局对象
-
let在同一个作用域不允许重复声明变量
-
let不会有变量提升,不能在声明变量之前使用变量
实际上let声明的变量在底层实现上也会变量提升,但是提升后会将其放到“暂时性死区” 如果变量位于暂时性死区,则会报错:ReferenceError: Cannot access 'a' before initialization,当代码运行到该变量声明语句时,会将该变量从暂时性死区中移除
const:
-
声明变量,必须在声明时就要赋值
-
let与const的区别就是const声明的变量不能更改
-
常量不可变:指的是声明常量的内存空间不变,并不能保证内存空间的地址指向的其他的内存空间
const a = { name:'wzq', age:10 } a.name = 'wyf'
继承模式
-
利用原型来实现继承,但是有显著的缺点,原型上有多个属性的时候,只想继承一个无法实现。
-
借用构造函数,利用call回调来实现继承,实例代码如下:
function Person(name,age){ this.name = name this.age = age } function Student(name,age,className,score){ Person.call(this,name,age)//简化操作 person函数执行就是将name和age数据赋值给this的name和age属性 this.className = className this,score = score }无法实现服用,每次都要执行两次函数,影响性能
-
原型式继承
-
圣杯模式 Father.prototype.name = 'zhang'; function Father(){
} function F(){} F.prototype = Father.prototype;
function Son(){ }Son.prototype = new F(); 解释: 1.先创建一个中间层的构造函数F,将Father的原型对象赋值给F函数,现在F继承了Father的原型对象的属性和方法。 2.Son的原型对象是由F构造函数new出来的对象。F函数new的对象继承了Father的原型对象的属性和方法。 3.Son的原型对象拥有了Father原型对象的属性和方法。当修改或添加Son原型对象的属性和方法的时候,修改的是 F函数new的对象,该对象是一个独立的对象(修改的时候Father原型对象不会受到影响),修改的时候Father原型对象不会受到影响 抽象成一个函数,封装功能。 function inherit(Target,Origin){ function F(){}; F.prototype = Orgin.prototype; Target.prototype = new F(); Target.prototype.constructor = Target;//没有这一步的话,son的construcotr会指向Father 这一步可以将son的原型对象归位 }
CSS重磅难点:水平居中与垂直居中
内联元素居中布局
水平布局
- 行内元素可设置为:text-align:center;
- flex布局设置父元素:display:flex;justify-content:center;
垂直布局
- 单行文本父元素确定高度:height
- 多行文本父元素确定高度:display:table-cell; vertical-align:middle;
块级元素集中布局
-
水平居中
- 定宽:margin:0 auto;
- 不定宽:
-
垂直居中
- position:absolute; 调整top,left,margin-left,margin-top(定高)
- position:fixed; 设置margin:auto;(定高)
- display:table-cell vertical-align:middle
- transform:translate(x,y)
- flex(不定宽,不定高)
- grid(不定宽,不定高)
两栏布局
- 通过浮动来实现两栏布局
.box{
overflow: hidden;
}
.left{
width: 200px;
height: 400px;
background-color: red;
float: left;
}
.right{
margin-left: 210px;
height: 200px;
background-color: green;
}
<div class="box">
<div class="left"></div>
<div class="right"></div>
</div>
2.通过flex来实现两栏布局
.box{
display: flex;
}
.left{
width: 200px;
height: 400px;
background-color: red;
}
.right{
height: 200px;
background-color: green;
flex: 1;
}
<div class="box">
<div class="left"></div>
<div class="right"></div>
</div>
3.通过grid来实现
圣杯布局
一行三个元素,两边的宽度固定中间的宽度自适应
用flex实现
.box{
display: flex;
justify-content: space-between;
}
.left{
width: 200px;
height: 400px;
background-color: red;
}
.middle{
flex: 1;
height: 400px;
background-color: green;
}
.right{
width: 200px;
height: 400px;
background-color: blue;
}
<div class="box">
<div class="left">左边</div>
<div class="middle">内容</div>
<div class="right">右边</div>
</div>
数组去重
1.双循环去重法
先定义一个包含原始数组第一个元素的数组,然后遍历原始数组,将原始数组中的每个元素与新数组中的每个元素进行比对,如果不重复则添加到新数组中,最后返回新数组
2.set与去重法
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
return [...new Set(arr)]//用解构赋值将set转换成数组
return Array.from(new Set(arr))//用Array.from方法把set对象变成数组
}
3.利用对象属性进行去重
const arr = [1,2,2,3,4,4,5]
let obj = {}
let res = []
for(let i = 0 ;i<arr.length;i++){
if(!obj[arr[i]]){
res.push(arr[i])
obj[arr[i]] = true
}
else{
}
}
-
indexof方法去重
const arr = [1,2,2,3,4,4,5]
let obj = {}
let res = []
for(let i = 0 ; i<arr.length ; i++){
if(res.indexOf(arr[i])==-1){
res.push(arr[i])
}
}
5.相邻元素去重
let arr = [1,2,2,3,4,4,5]
let res = []
arr = arr.sort()
for(let i = 0; i<arr.length ; i++){
if(arr[i]!==arr[i-1]){
res.push(arr[i])
}
}
js数组不会报越界错误,可能是因为js数组的底层是hash表