Appearance
HTML语义化
HTML语义化就是让页面内容结构化,具有如下优点:
1、利于SEO,搜索引擎根据标签来确定上下文和各个关键字的权重
2、方便阅读、样式丢失时能让页面呈现清晰的结构
3、有利于开发和维护,语义化更具有可读性,代码更好维护,与CSS3关系更和谐
盒子模型
盒模型分为标准盒模型和怪异盒模型(IE模型)
box-sizing:content-box // 标准盒模型
box-sizing:border-box // 怪异盒模型
标准盒模型:元素的宽度等于style里面的width+margin+border+padding宽度
怪异盒模型:元素宽度等于style里的width宽度
注意:如果在设计页面时,发现内容区被撑爆了,先检查一下box-sizing是什么,最好在引用reset.css的时候,就对border-sizing进行统一设置,方便管理
rem和em的区别
rem是根据根的font-size变化,而em是根据父级的font-size变化
rem:相对于根元素html的font-size
em:相对于父级元素计算
CSS选择器
通配符:*
ID选择器:#ID
类选择器:.class
元素选择器:p、a等
伪类选择器:a:hover等
属性选择器:input[type = "text"]等
CSS选择器权重
!important -> 行内样式 -> #id -> .class -> 元素和伪元素 -> * -> 继承 -> 默认
CSS新特性
transition:过渡
transform:旋转
animation:动画
gradient:渐变
shadow:阴影
border-radius:圆角
行内元素和块级元素
行内元素(display:inline):宽度和高度是由内容决定的,与其他元素共占一行的元素,例如span、i、a等
块级元素(display:block):默认宽度由父容器决定,默认高度由内容决定,独占一行并且可以设置宽高的元素,例如p、div、ul等
我们经常使用css的display:inline-block,使他们拥有更多的状态
绝对定位和相对定位的区别
css
position:absolute // 绝对定位:是相对于元素最近的已经定位的组先元素
postition:relative // 相对定位:相对定位是相对于元素在文档中的初始位置Flex布局
Flex布局元素,称为Flex容器,简称"容器"。它的所有子元素自动成为容器元素,简称"项目"。
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的排列方式:从左到右;交叉轴的排列方式:从上到下;
闭包
- 函数内再嵌套函数
- 内部函数可以引用外层的参数和变量
- 参数和变量不会被垃圾回收机制回收
对闭包的理解
使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄漏。在js中,函数即闭包,只有函数才会产生作用域的概念。
闭包的最大用处有两个,一个是可以读取函数内容的变量,另一个就是让这些变量始终在内存中
闭包的另一个用处是封装对象的私有属性和私有方法
闭包的好处
能够实现封装和缓存等
闭包的坏处
就是消耗内存、不正当使用会造成内存溢出的问题
使用闭包的注意点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE可能导致内存泄漏
解决办法是:在退出函数之前,将不使用的局部变量全部删除
闭包的经典问题
javascript
for(var i = 0;i < 3;i++){
setTimeout(function(){
console.log(i)
},1000)
}
// 3、3、3两种解决办法
1、使用Let
javascript
for(let i =0;i < 3;i++){
setTimeout(function(){
console.log(i)
},1000)
}
// 在这里每个let和代码块结合起来形成块级作用域,当setTimeout()打印时,会寻找最近的块级作用域中的i,所以依次打印出0、1、2
// 即代码还是先执行 for 循环,但是当 for 结束执行到了 setTimeout 的时候,它会做个标记,这样到了 console.log(i) 中,i 就能找到这个块中最近的变量定义2、使用立即执行函数解决闭包问题
javascript
for(let i = 0; i < 3; i++){
(function(i){
setTimeout(function(){
console.log(i)
},1000)
})(i)
}JS的基本规范
1、不要在同一行声明多个变量 2、请使用===/!==来比较true/false或者数值 3、使用对象字面量替代new Array这种形式 4、不要使用全局变量 5、Switch语句必须带有default分支 6、函数不应该有时候有返回值,有时候没有返回值 7、For循环必须使用大括号 8、IF语句必须使用大括号 9、for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染
JS引用方法
行内引入
html
<body>
<input type="button" onclick="alert('行内引入')" value="按钮"/>
<button onclick="alert(123)">点击我</button>
</body>内部引入
javascript
<body>
<div></div>
<script type="text/javascript" src="./js/index.js"></script>
</body>1、不推荐写行内或者HTML中插入script,因为浏览器解析顺序缘故,如果解析到死循环之类的JS代码,会卡住页面2、建议在onload事件之后,即等HTML、CSS渲染完毕再执行代码
JS的基本数据类型
Undefined|Null|Boolean|Number|String|Symbol
数组操作
map:遍历数组,返回回调返回值组成的新数组
forEach:无法break,可以用try/catch中throw new Error来停止
filter:过滤
some: 有一项返回true,则整体为true every: 有一项返回false,则整体为false
join: 通过指定连接符生成字符串
push / pop: 末尾推入和弹出,改变原数组, 返回推入/弹出项【有误】
unshift / shift: 头部推入和弹出,改变原数组,返回操作项【有误】
sort(fn) / reverse: 排序与反转,改变原数组
concat: 连接数组,不影响原数组, 浅拷贝
slice(start, end): 返回截断后的新数组,不改变原数组
splice(start, number, value...): 返回删除元素组成的数组,value 为插入项,改变原数组
indexOf / lastIndexOf(value, fromIndex): 查找数组项,返回对应的下标
reduce / reduceRight(fn(prev, cur), defaultPrev): 两两执行,prev 为上次化简函数的return值,cur 为当前值(从第二项开始)
JS的内置对象
Object是JavaScript中所有对象的父对象
数据封装对象:Object、Array、Boolean、Number和String
其他对象:Function、Arguments、Math、Date、RegExp、Error
get请求传参长度的误区
误区:我们经常说get请求参数的大小存在限制,而post请求的参数大小是无限制的
实际上HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对get请求参数的限制是来源与浏览器或web服务器,浏览器或web服务器限制了url的长度。为了明确这个概念,我们必须再次强调下面几点:
1、HTTP 协议 未规定 GET 和POST的长度限制
2、GET的最大长度显示是因为 浏览器和 web服务器限制了 URI的长度
3、不同的浏览器和WEB服务器,限制的最大长度不一样
4、要支持IE,则最大长度为2083byte,若只支持Chrome,则最大长度 8182byte
补充get和post请求在缓存方面的区别
- get请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存。
- post不同,post做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此get请求适合于请求缓存。
原型和原型链
概念
每个对象都辉在其内部初始化一个属性,就是Prototype(原型),当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就辉去prototype里找个属性,这个prototype又会有自己的prototype,于是就这样一直找下去
原型和原型链的关系
javascript
instance.constructor.prototype = instance.__proto__特点
Javascript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变
当我们需要一个属性的时,Javascript引擎会先看当前对象中是否有这个属性, 如果没有的
就会查找他的Prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象
组件化和模块化
组件化
有时候页面代码量太大,逻辑太多或者同一个功能组件在许多页面均有使用,维护起来相当复杂,这个时候,就需要组件化开发来进行功能拆分、组件封装,已达到组件通用性,增强代码可读性,维护成本也能大大降低
模块化
早期的javascript版本没有块级作用域、没有类、没有包、也没有模块,这样会带来一些问题,如复用、依赖、冲突、代码组织混乱等,随着前端的膨胀,模块化显得非常迫切
模块化的几种方法
函数封装
javascript
let Module = {
var1:1,
var2:2,
fn1:function(){},
fn2:function(){}
}总结:这样避免了变量污染,只要保证模块名唯一即可,同时同一模块内的成员也有了关系
缺陷:外部可以睡意修改内部成员,这样就会产生意外的安全问题
立即执行函数表达式(IIFE)
javascript
var myModule = (function(){
var var1 = 1;
var var2 = 2;
function fn1(){
}
function fn2(){
}
return {
fn1: fn1,
fn2: fn2
};
})();总结:这样在模块外部无法修改我们没有暴露出来的变量、函数
缺点:功能相对较弱,封装过程增加了工作量,仍会导致命名空间污染可能、闭包是有成本的
图片的预加载和懒加载
- 预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染
- 懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数
两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。预加载则会增加服务器前端压力,懒加载对服务器有一定的缓解压力作用。
事件冒泡和事件捕获
事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题。
html
<div id=”outer“>
<p id="inner">Click me!</p>
</div>上面的代码当中一个div元素当中有一个p子元素,如果两个元素都有一个click的处理函数,那么我们怎么才能知道哪一个函数会首先被触发呢?
为了解决这个问题微软和网景提出了两种几乎完全相反的概念。
事件冒泡
微软提出了名为事件冒泡(event bubbling)的事件流。事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。
因此上面的例子在事件冒泡的概念下发生click事件的顺序应该是
p -> div -> body -> html -> document
事件捕获
网景提出另一种事件流名为事件捕获(event capturing)。与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。
上面的例子在事件捕获的概念下发生click事件的顺序应该是
document -> html -> body -> div -> p
事件冒泡和事件捕获过程图:
1-5是捕获过程,5-6是目标阶段,6-10是冒泡阶段;
addEventListener的第三个参数
DOM2级事件”中规定的事件流同时支持了事件捕获阶段和事件冒泡阶段,而作为开发者,我们可以选择事件处理函数在哪一个阶段被调用。
addEventListener方法用来为一个特定的元素绑定一个事件处理函数,是JavaScript中的常用方法。addEventListener有三个参数:
element.addEventListener(event,function,useCapture)
| 参数 | 描述 |
|---|---|
| event | 必须。字符串,指定事件名。 注意: 不要使用 "on" 前缀。 例如,使用 "click" ,而不是使用 "onclick"。 提示: 所有 HTML DOM 事件,可以查看完整的 HTML DOM Event 对象参考手册。 |
| function | 必须。指定要事件触发时执行的函数。 当事件对象会作为第一个参数传入函数。 事件对象的类型取决于特定的事件。例如, "click" 事件属于 MouseEvent(鼠标事件) 对象。 |
| useCapture | 可选。布尔值,指定事件是否在捕获或冒泡阶段执行。 可能值:true - 事件句柄在捕获阶段执行(即在事件捕获阶段调用处理函数)false- false- 默认。事件句柄在冒泡阶段执行(即表示在事件冒泡的阶段调用事件处理函数) |
事件代理
在实际的开发当中,利用事件流的特性,我们可以使用一种叫做事件代理的方法。
html
<ul class="color_list">
<li>red</li>
<li>orange</li>
<li>yellow</li>
<li>green</li>
<li>blue</li>
<li>purple</li>
</ul>
<div class="box"></div>我们想要在点击每个 li 标签时,输出li当中的颜色(innerHTML) 。常规做法是遍历每个 li ,然后在每个 li 上绑定一个点击事件:
javascript
var color_list = document.querySelector(".color_list");
var colors = color_list.getElementsByTagName("li");
var box = document.querySelector(".box");
for(var n = 0 ; n < colors.length; n++){
colors[n].addEventListener("click",function(){
console.log(this.innerHTML)
box.innerHTML="该颜色为 "+this.innerHTML;
})
}这种做法在 li 较少的时候可以使用,但如果有一万个 li ,那就会导致性能降低(少了遍历所有 li 节点的操作,性能上肯定更加优化)。
这时就需要事件代理出场了,利用事件流的特性,我们只绑定一个事件处理函数也可以完成:
javascript
function colorChange(e){
var e=e||window.event;//兼容性的处理
if(e.target.nodeName.toLowerCase()==="li"){
box.innerHTML = "该颜色为 "+e.target.innerHTML;
}
}
color_list.addEventListener("click",colorChange,false)由于事件冒泡机制,点击了 li 后会冒泡到 ul ,此时就会触发绑定在 ul 上的点击事件,再利用 target 找到事件实际发生的元素,就可以达到预期的效果。
使用事件代理的好处不仅在于将多个事件处理函数减为一个,而且对于不同的元素可以有不同的处理方法。假如上述列表元素当中添加了其他的元素节点(如:a、span等),我们不必再一次循环给每一个元素绑定事件,直接修改事件代理的事件处理函数即可。
(1)toLowerCase() 方法用于把字符串转换为小写。语法:stringObject.toLowerCase()
返回值:一个新的字符串,在其中 stringObject 的所有大写字符全部被转换为了小写字符。
(2)nodeName 属性指定节点的节点名称。如果节点是元素节点,则 nodeName 属性返回标签名。如果节点是属性节点,则 nodeName 属性返回属性的名称。对于其他节点类型,nodeName 属性返回不同节点类型的不同名称。
阻止事件冒泡
给子级加event.stopPropagation()
javascript
$('#div1').mousedown(function(e){
var e = event || window.event
event.stopPropagation()
})在事件处理函数中返回false
javascript
$("#div1").mousedown(function(event){
var e=e||window.event;
return false;
});但是这两种方式是有区别的。return false 不仅阻止了事件往上冒泡,而且阻止了事件本身(默认事件)。event.stopPropagation()则只阻止事件往上冒泡,不阻止事件本身。
event.target==event.currentTarget,让触发事件的元素等于绑定事件的元素,也可以阻止事件冒泡;
阻止默认事件
(1)event.preventDefault()
(2)return false
This指向问题
this总是指向函数的直接调用者(而非间接调用者)
如果有new关键字,this指向new出来的那个对象
在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window
防抖和节流
防抖概念
防抖具体指的是某个函数在某段时间内,无论触发了多少次回调,都只执行最后一次。假如我们设置了一个等待时间 3 秒的函数,在这 3 秒内如果遇到函数调用请求就重新计时 3 秒,直至新的 3 秒内没有函数调用请求,此时执行函数,不然就以此类推重新计时
节流原理
防抖实现原理就是利用定时器,函数第一次执行时设定一个定时器,并且通过闭包缓存起来,之后调用时发现已经设定过定时器就清空之前的定时器,并重新设定一个新的定时器,如果存在没有被清空的定时器,当定时器计时结束后触发函数执行。
javascript
/*
* 防抖函数
* @param fn 事件触发的操作
* @param delay 多少毫秒内连续触发事件,不会执行
* @returns {Function}
*/
function debounce(fn,delay) {
let timer = null; //通过闭包缓存了一个定时器
return function () {
const args = [...arguments];
const that = this
timer && clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(that,args);
},delay);
}
}
window.onscroll = debounce(function () {
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
},200)