赞
踩
视频标签:<video src=""></video>
标签内部的属性
音频标签:<audio> <source src="" type=""> </audio>
音频标签的属性和视频标签的属性类似,但是poster属性不可以使用
优点:
新增标签:
行内元素:相邻的行内元素会排列在同一行,不会独占一行,设置宽高无效
常见行内元素:a、br、img、input、textarea、span
块元素:独占一行,可设置宽高等属性
常见块元素:div、h1-h6、hr、p、ul、table、
iframe元素会创建包含另一个文档的内联框架
缺点:
Doctype声明于文档的最前面,告诉浏览器以何种方式来渲染页面,有严格模式和混杂模式。
严格模式的排版和JS运作模式是以浏览器支持的最高标准进行。
混杂模式,向后兼容,模拟老式浏览器,防止浏览器无法兼容页面
渐变可以设置一些复杂的背景颜色,可以实现从一个颜色向其他颜色过渡的效果,渐变是图片,需要通过background-image来设置
linear-gradient 线性渐变
颜色沿着一条直线发生变化,例如:linear-gradient(red,yellow) 红色在开头,黑色在结尾,中间是过渡区域,线性渐变的开头,我们可以指定一个渐变的方向。通过to left/right/bottom/top来指定。deg表示度数,turn表示圈。
radial-gradient 径向渐变
该渐变是有中心向四周扩散,默认情况下径向渐变的形状是根据元素的形状来计算的,语法:radial-gradient(大小 at 位置,颜色 位置)
一个盒子从外到内可分为4个部分,margin外边距,border边框,padding内边距,content内容。默认情况下,盒子的宽高属性只是设置content的宽和高。
padding和border会影响可见框的总尺寸,margin不会。
盒子真正的高度应该是:内容高度+padding+border
画图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-58aKVEgD-1630298526690)(D:\fore-end\Preparation for Job interview\images\盒子模型.jpg)]
高度塌陷问题:父元素没有设置高度,则父元素的高度默认被子元素撑开,当所有子元素开启浮动的时候,子元素就会脱离文档流,则父元素就会产生高度塌陷的问题,影响页面的布局。
清除浮动的方式:
给父元素单独定义高度
父元素开启Block Formatting Context 简称BFC
可以直接在高度塌陷的父元素的最后,添加一个空白的div,由于这个div并没有浮动,所以他是可以撑开父元素的高度的,然后对其进行清除浮动,这样可以通过这个空白的div来撑开父元素的高度。使用这种方式虽然可以结局问题,但是会在页面中添加多余的结构。
可以通过after伪类元素的最后添加一个空白元素,将其转换成一个块元素,然后对其清除浮动,这样做和添加一个div的原理一样,可以达到一个相同的效果,而且不会在页面中添加多余的div。为最推荐使用的方式。
例如:.clearfix:after{
content:"";
display:block;
clear:both;
}
经过修改的clearfix是一个多功能的,既可以解决高度塌陷,又可以确保父元素和子元素的垂直外边距不会重叠。
.clearfix:before, .clearfix:after{
content:"";
display:table;
clear:both;
}
使用CSS的overflow属性,给浮动元素的容器添加overflow:hidden或者overflow:auto,在添加了overflow属性后,浮动元素又回到了容器层,把容器高度撑起,达到了清除浮动效果。
定位就是将指定元素摆放到网页的任意位置。通过position来设置元素的定位,position有以下可选值
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <style> #box{ width: 1000px; background-color: greenyellow; } #child{ width: 100px; margin: auto; /* float: left; */ } #box1{ width: 1000px; background-color: yellowgreen; text-align: center; } #child1{ width: 100px; display: inline-block; /* float: left; */ } </style> <body> <div id="box"> <div id="child">我是子元素</div> </div> <div id="box1"> <div id="child1">我是子元素</div> </div> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> #box1{ width: 500px; height: 800px; background-color: yellowgreen; position: relative; } #child1{ width: 100px; height: 100px; background-color: brown; position: absolute; top: 50%; transform: translateY(-50%); } #box2{ width: 500px; height: 800px; background-color: yellowgreen; display: flex; } #child2{ width: 100px; height: 100px; background-color: brown; align-self: center; } </style> </head> <body> <!-- 方式一 --> <div id="box1"> <div id="child1"></div> </div> <hr> <!-- 方式二 --> <div id="box2"> <div id="child2"></div> </div> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> #box1{ width: 1000px; height: 400px; background-color: yellowgreen; position: relative; } #child1{ width: 100px; height: 100px; background-color: pink; position: absolute; top: 0; right: 0; left: 0; bottom: 0; margin: auto; } #box2{ width: 1000px; height: 400px; background-color: yellowgreen; display: table-cell; vertical-align: middle; } #child2{ width: 100px; height: 100px; background-color: pink; margin: auto; } #box3{ width: 1000px; height: 400px; background-color: yellowgreen; } #child3{ width: 100px; height: 100px; background-color: pink; position: relative; top: 50%; left: 50%; transform:translate(-50%,-50%); } #box4{ width: 1000px; height: 400px; background-color: yellowgreen; position: absolute; } #child4{ width: 100px; height: 100px; background-color: pink; position: relative; top: 50%; left: 50%; transform:translate(-50%,-50%); } #box5{ width: 1000px; height: 400px; background-color: yellowgreen; display: flex; justify-content: center; align-items: center; } #child5{ width: 100px; height: 100px; background-color: pink; } </style> </head> <body> <!-- 方式1 --> <div id="box1"> <div id="child1"></div> </div> <hr> <!-- 方式2 --> <div id="box2"> <div id="child2"></div> </div> <hr> <!-- 方式3 --> <div id="box3"> <div id="child3"></div> </div> <hr> <!-- 方式4 --> <div id="box4"> <div id="child4"></div> </div> <hr> <!-- 方式5 --> <div id="box5"> <div id="child5"></div> </div> <hr> </body> </html>
元素选择器,语法:标签名{}
id选择器,通过元素的id属性值选中唯一的一个元素。语法:#id属性值{}
并集选择器,同时选中多个选择器对应的元素,语法:选择器1,选择器2,选择器N{}
交集选择器,可以选中满足多个选择器的元素,语法:选择器1选择器2选择器N{}
通配选择器,选中页面中的所有元素,语法:*{}
类选择器,为元素设立class属性值,通过元素的class属性值选中一组元素,语法:.class属性值{}
后代元素选择器,选中指定元素的指定后代元素,语法:祖先元素 后代元素{}
子元素选择器,选中指定父元素的指定子元素,语法:父元素>子元素{}
伪类选择器,伪类专门用来表示元素的一种特殊状态
涉及到超链接的伪类一共有4个,这四个的优先级是一样的,顺序为:link、visited、hover、active。
属性选择器:可以根据元素中的属性或属性值来选择去指定元素
语法:
title属性,这个属性可以给任何标签指定。当鼠标移入到元素上时,元素中的title属性值会将作为提示文字显示。
子元素选择器
兄弟元素选择器
否定伪类:可以从已选中的元素中剔除某些元素
内联样式,优先级1000
id选择器,优先级100
类和伪类,优先级10
元素选择器,优先级1
通配,优先级0
继承的样式没有优先级
注:当选择器中包含多种选择器时,需要将多种选择器的优先级相加然后在比较,但是,选择器优先级计算不会超过他的最大数量级,如果选择器的优先级一样,则使用靠后的优先级。在样式的最后,添加一个!important,此时该样式将获得一个最高的优先级,优先于所有的样式甚至超过内联样式
CSS继承特性主要是文本方面
flex弹性盒可以使元素具有弹性,让元素跟随页面大小的改变而改变。
布局原理:通过给父盒子添加flex属性,来控制盒子的位置和排列方式
使用弹性盒,必须先将一个容器设置为弹性容器,通过display来设置弹性容器。
主轴:弹性元素的排列方向为主轴
侧轴:与主轴反向垂直的方向为侧轴
当设置为弹性容器时,可以指定以下属性
flex-direction 用来指定容器中弹性元素的排列方式,可选值
flex-wrap 设置弹性盒子的子元素超出父容器时是否换行
flex-flow, 是flex-direction和flex-wrap的简写形式
justify-content用来分配主轴上的空白空间,可选值:
align-items,元素在侧轴上如何对齐,元素之间的关系
**弹性元素:**弹性容器的直接子元素,一个元素可以同时是弹性容器和弹性元素
弹性元素的属性
flex-grow 指定弹性元素的伸展系数,当父元素有多余的空间时,子元素会按照比例进行分配。
flex-shrink 指定弹性元素的收缩系数,当父元素的空间不足以容纳所有的子元素时,子元素会按照比例进行收缩。
align-self,用来覆盖当前弹性元素上的align-items。
flex-basis,指定的是元素在主轴上的基础长度,如果主轴是横向的,则该值指定的就是元素的宽度;如果主轴是纵向的,则该值指定的就是元素的高度;默认值是auto,表示参考元素自身的高度或宽度,如果传递了一个具体的数值,则以该值为准。
flex为简写属性,可以设置弹性元素的的三个样式。
order 设置弹性元素的顺序。顺序越小,排列越靠前,默认为0
块格式化上下文是css可视化渲染的一部分,它是一块区域,规定了内部块盒的渲染方式,以及浮动相互之间的影响关系,当元素设置了overflow样式且值不为visible时,元素就构建了一个BFC,BFC在计算高度时,内部浮动元素的高度也计算在内,也就是说技术BFC区域内只有一个浮动元素,BFC的高度也不会发生塌陷,所以达到了清除浮动的目的。
三角形原理:边框的均分原理
div {
width:0px;
height:0px;
border-top:10px solid red;
border-right:10px solid transparent;
border-bottom:10px solid transparent;
border-left:10px solid transparent;
}
link标签属于html标签,import是css提供的;页面被加载时,link会被同时加载,而import引用的css会等到页面加载结束后加载;link方式的样式权重高于import。
BFC块级格式化上下文,页面的隐含属性,全名:Block Formatting Context ,用于清除浮动,防止margin重叠等。
当开启BFC以后,元素会具备以下特性:
display: -webkit-box
-webkit-box-orient:vertical
-webkit-line-clamp:3
overflow:hidden
DOM的变化影响到了预算的几何属性,比如宽高,浏览器重新计算元素的几何属性,其他元素的几何属性也会受到影响,浏览器需要重新构造渲染树,这个过程称之为重排;浏览器将受到影响的部分重新绘制在屏幕上的过程称为重绘。
引起重排重绘的原因:
重排一定导致重绘,重绘不一定导致重排
减少重绘重排的方法:
基本数据类型:
(对象)引用类型
判断:
typeof:
instanceof:
===
undefined与null的区别?
创建XMLHTTPRequest对象
var xhr = new XMLHttpRequest()
使用open设置请求信息
xhr.open(method, url);
//可以设置请求头,一般不设置
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
使用send发送请求
xhr.send(body) //get 请求不传 body 参数,只有 post 请求时传入
接收响应,更新页面
//xhr.responseXML 接收 xml 格式的响应数据
//xhr.responseText 接收文本格式的响应数据
xhr.onreadystatechange = function (){
if(xhr.readyState == 4 && xhr.status == 200){
var text = xhr.responseText;
console.log(text);
}
}
常见状态码:
NaN 非数字,但是用typeof检测是number类型
利用NaN是唯一 一个不等于自身的特点去判断 NaN === NaN ——false
利用ES6的Object.is()方法,判断两个值是否相等
闭包就是能够读取嵌套函数内部变量的函数,子函数所在的父函数的作用域不会被释放。
如何产生闭包?
闭包是什么?
注:闭包存在于嵌套的内部函数中
常见的闭包
产生闭包的条件
闭包的特性
使用:
优点:
缺点
会造成内存泄漏,什么是内存泄漏?
内存泄漏是指一块被分配的内存既不能使用又不能回收,直到浏览器进程结束
释放内存的方法:赋值为null
事件委托就是利用事件冒泡,只制定一个事件处理程序,就可以管理某一类型的所有事件。
事件委托称事件代理,是JS中很常用的绑定事件的技巧,事件委托就是把原本需要绑定在子元素的事件委托给父元素,让父元素监听该事件,事件委托的原理就是DOM元素的事件的冒泡
当一个事件触发后,户籍在子元素和父元素之间传播,这种传播分为3个阶段
事件委托/事件代理 就是利用事件的冒泡机制把里层需要响应的事件绑定到外层
session与cookie的区别和联系
区别:
联系:
sessionStorage、localStorage和cookie的区别
共同点:都是保存在浏览器端、且同源的
区别:
浏览器本地存储与服务器端存储的区别
其实数据既可以在浏览器本地存储,也可以在服务器端存储
浏览器可以保存一些数据,需要的时候直接从本地存取,sessionStorage、localStorage和cookie都是由浏览器存储在本地的数据
服务器端也可以保存所有用户的所有数据,但需要的时候浏览器要向服务器请求数据。
1、服务器端可以保存用户的持久数据,如数据库和云存储将用户的大量数据保存在服务器端
2、服务器端也可以保存用户的临时会话数据,服务器端的session机制,如jsp的session对象,数据保存在服务器上,
实际上,服务器和浏览器之间仅需传递session id即可,服务器根据session id找到对应用户的session对象,会话数据仅在一段时间内有效,这个时间就是server端设置的session有效期
服务器端保存所有的用户的数据,所以服务器端的开销较大,而浏览器端保存则把不同用户需要的数据分别保存在用户各自的浏览器中,浏览器端一般只用来存储小数据,而非服务可以存储大数据或小数据服务器存储数据安全一些,浏览器只适合存储一般数据
面向对象是一种思想,是基于面向过程而言的,就是说面向对象是将功能等通过对象来实现,将功能封装进对象之中,让对象去实现具体的细节。这种思想是将数据作为第一位,这是对数据一种优化,操作起来更加方便,简化了过程
JS本身是没有class类型的,但是每个函数都一个prototype属性,prototype指向一个对象,当函数作为构造函数时,prototype就起到类似于class的作用
面向对象的三大特性
原型prototype:任何对象实例都有一个原型,也叫原型对象,原型对象由对象的内置属性_proto_
指向它构造函数的prototype
指向的对象,即任何对象都是由一个构造函数创建的,但是不是每一个对象都有prototype
,只有方法才有prototype
显式原型与隐式原型
每个构造function都有一个prototype
,即为显式原型
每个实例对象都有一个_proto_
,即为隐式原型
对象的隐式原型的值为其构造函数的显式原型的值
总结:
_proto_
属性:创建对象时自动添加,默认值为构造函数的prototype属性值_proto_
隐式原型指向它构造函数的prototype
显式原型<script> // 定义构造函数 function Fn(){ // 内部语句:this.prototype = {} } // 1.每个函数function都有一个prototype,即为显示原型属性,默认指向一个空的Object对象 console.log(Fn.prototype); // 2.每个实例对象都有一个__protp__,可称为隐式原型 // 创建实例对象 var fn = new Fn(); // 内部语句:this.__proto__ = Fn.prototype console.log(fn.__proto__); // 3.对象的隐式原型的值为其对应构造函数的显示原型的值 console.log(Fn.prototype === fn.__proto__); //true // 给原型对象添加方法 Fn.prototype.test = function(){ console.log("test()"); } // 通过实例调用原型的方法 fn.test(); </script>
显示原型与隐式原型的内存结构图
原型链
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
原型链的核心就是依赖对象的_proto_
的指向,当自身不存在某一属性时,就会沿着_proto_
这条链去查找创建对象的构造函数,一直到Object,此时Object上就没有_proto_
的指向了。
因为_proto_
实际上找的是prototype,所以我们只要找到这条链上的构造函数的prototype。原型链的尽头是Object,Object的prototype是没有_proto_
属性的,它为null。
每个构造函数都有一个原型对象,原型对象都包含了一个构造函数的指针,而实例都包含指向原型对象内部的指针。我们让原型对象1等于另一个原型对象的实例2,此时原型对象2将包含一个指向原型对象1的指针,再让原型对象2的实例等于原型对象3,这样层层递进就构成了实例和原型的链条,这就是原型链的概念。
<script> // console.log(Object); // console.log(Object.prototype); console.log(Object.prototype.__proto__); function Fn(){ this.test1 = function(){ console.log("test1()"); }; } console.log(Fn.prototype); Fn.prototype.test2 = function(){ console.log("test2()"); }; var fn = new Fn(); fn.test1(); fn.test2(); console.log(fn.toString()); console.log(fn.test3); // fn.test3(); /* 1.函数的显示原型指向的对象默认是空Object实例对象(但Object不满足) */ console.log(Fn.prototype instanceof Object); //true console.log(Object.prototype instanceof Object); //false console.log(Function.prototype instanceof Object); //true /* 2.所有函数都是Function的实例(包含Function) */ console.log(Function.__proto__ === Function.prototype); /* Object的原型对象是原型链的尽头 */ console.log(Object.prototype.__proto__); //null </script>
原型链图解
原型继承:
Promise是JS中进行异步编程的解决方案,相比回调函数和事件更加合理强大,从语法上讲,promise是一个构造函数,从功能上讲,promise对象用来封装一个异步操作并可以获取其结果。
Promise有3中状态
pending,也叫等待状态
fulfiled,成功状态
rejected,失败状态
状态一旦改变,就不会再变,无论成功、失败,都会得到一个结果数据,成功的结果数据一般称为value,失败的结果数据一般称为reason
Promise的2个特点
Promise的3个缺点
用Promise来解决什么问题?
Promise是用来解决两个问题的:
支持链式调用,解决回调地狱,代码难以维护
什么是回调地狱?
回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件。
promise可以支持多并发的请求,获取并发请求中的数据,这个promise可以解决异步的问题,本身不能说promise是异步的
Promise的几个关键问题
如何改变promise的状态?
一个promise指定多个成功、失败的回调函数,都会调用吗?
当promise改变为对应状态时都会调用
改变promise状态和指定回调函数谁先谁后?
promise.then()返回的新promise的结果状态由什么决定?
简单表达:由then()指定的回调函数执行的结果决定
详细表达:
promise如何串联多个操作任务?
promise的异常穿透?
中断promise链?
当使用promise的then()的链式调用时,在中间中断,不在调用后面的回调函数。
解决方案:在回调函数中返回一个pending状态的promise对象
async与await的用法
async
awiat
注:
new操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象
apply:调用一个对象的方法,用另一个对象替换当前对象
call:调用一个对象的方法,用另一个对象替换当前对象
通过apply和call改变函数的this指向,他们两个函数的第一个参数都是表示要改变指向的那个对象,对于第二个参数,apply是数组,而call则是arg1,arg2…这种形式。
通过bind改变this作用域会返回一个新的函数,这个函数不会马上执行
clientHeight:表示的是可视区域的高度,不包含border和滚动条
offsetHeight:表示可视区域的高度,包含border和滚动条
scrollHeight:表示了所有区域的高度,包含了因为滚动被隐藏的部分
clientTop:表示边框border的高度,在未指定的情况下一般为0
offsetTop:当前元素距浏览器边界的偏移量
scrollTop:表示已经滚动到元素的上边界的高度
首先需要用到3个事件,mousedown,mousemove,mouseup
当鼠标点击按下的时候,需要一个tag标识此时已经按下,可以执行mousemove里面的具体方法。clientX,clientY标识的是鼠标的横纵坐标,并且我们用offsetX和offsetY来表示元素的初始坐标。
移动的距离应该是:鼠标移动时候的坐标-鼠标按下去的坐标
定位的信息为:鼠标移动时候的坐标-鼠标按下去的坐标+元素初始情况下的offsetLeft
**注:**拖拽的同时是绝对定位,我们改变的是绝对定位条件下的left以及top等值
为什么需要垃圾回收机制?
由于字符串、对象、数组没有固定的大小,所以当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript每次创建字符串、数组、对象时,解释器都必须分配内存来储存那个实体,只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则JavaScript的解释器将会消耗完系统中所有的可用内存,造成系统崩溃。
JavaScript有自己的一套垃圾回收机制,JavaScript的解释器可以检测到任何时候程序不再使用一个对象,当他确定了一个对象是无用的时候,他就不需要这个对象,可以把它所占用的内存释放掉了。
垃圾回收机制的方法?
标记清除
这是最常见的垃圾回收方式,当变量进入环境时,就标记这个变量为“进入环境”,从逻辑上讲,永远不能释放进入环境的变量所占的内存,永远不能释放进入环境变量所占用的内存,只要执行流程进入相应的环境,就可以用到他们,当离开环境时,就标记为离开环境。
垃圾回收期在运行的时候会给存储在内存中的变量都加上标记,然后去掉环境变量中的变量,以及被环境变量中的变量所引用的变量,删除所有被标记的变量,删除的变量无法在环境变量中被访问,最后垃圾回收期完成了内存的清除工作,回收他们所占用的内存。
引用计数法
当声明一个变量,并用一个引用类型的值赋给变量时,这个值的引用次数为1;相反,如果包含了对这个值引用的变量又取得了另外一个值,则原先的引用之引用的次数就减1,当这个值的引用次数为0时,说明没办法再访问这个值了,就会把它所占的内存给回收劲来,这样垃圾收集器再运行的时候,就会释放引用次数为0的这些值。
但是用该方法会存在内存泄漏:
function problem(){
var objA = new Object();
var objB = new Object();
objA.someOtherObject = objB
objB.anotherObject = objA
}
上述例子:objA和objB通过各自的属性相互引用,这样的话,两个对象的引用次数都为2,再该方式中,由于函数执行之后,这两对象都离开了作用域,函数执行完之后,因计数不为0,这样的相互引用如果大量存在就会导致内存泄露。
假设有一个user对象
在ES5中可以通过Object.defineProperty来实现已有属性的监听
Object.defineProperty(user,'name',{
set:function(key,value){}
})
缺点:如果id不存在user对象中,则不能监听id的变化
在ES6中可以使用Proxy实现
var user = new Proxy({},{
set:function(targer,key,value,receiver){
}})
这样,即使属性id不在user中,通过user.id来定义也同样可以监听该属性的变化
原理:通过apply或者call方法
// 初始版本 Function.prototype.bind = function (obj,arg) { var arg = Array.prototype.slice.call(arguments,1) var context = this return function (newArg) { arg = arg.concat(Array.prototype.slice.call(newArg)) return context.apply(obj.arg) } } // 考虑到原型链 // 因为在new一个bind过程中生成的新函数,必须的条件是要继承原函数的原型 Function.prototype.bind = function (obj,arg) { var arg = Array.prototype.slice.call(arguments,1) var context = this var bound = function (newArg) { arg = arg.concat(Array.prototype.slice.call(newArg)) return context.apply(obj,arg) } var F = function () { F.prototype = context.prototype bound.prototype = new F() return bound } }
JS运行在客户端浏览器上,不用预编译,直接解析执行代码;是弱类型语言,较为灵活;与操作系统无关,跨平台的语言;脚本语言、解释性语言
为什么js是弱类型语言:弱类型语言实现是相对于强类型语言来说的,在强类型语言中,变量的类型有多种,不同的类型相互转换有时需要强制转换,而JS只有一种类型var,为变量赋值时会自动判断类型并转换,所以是所类型的。
在JavaScript中,this通常指向的是我们正在执行的函数本身,或者是,指向该函数所属的对象。
全局的this ==> 指向的是window
对象中的this ==> 指向的是其本身
事件中的this ==> 指向的是事件对象
深拷贝:指针赋值,并且内容拷贝
浅拷贝:知识简单的指针赋值
数组浅拷贝:如果是数组,可以使用数组的一些方法实现,slice(),concat()返回一个新数组的特性实现拷贝
数组深拷贝:用扩展运算符spread实现数组深拷贝,JSON.parse(JSON.stringify())不仅适用于数组,还适用于对象,不能拷贝函数、undefined,symbol。
for遍历自身对象和继承可枚举的属性,也就是说会包括那些原型链上的属性
map方法不会对空数组进行检测,map会返回一个新数组,不会对原数组产生影响。
同步(阻塞)
异步(非阻塞)
就好比两人一块上班:
同步和异步这两个关注的是在等待调用结果时的状态
回流:当render tree中的一部分或者全部因为元素的规模尺寸,布局,隐藏等改变,而需要重新构建,这就叫回流,每个页面至少需要一次回流,就是在页面第一次加载的时候,这个时候一定会发生回流,因为要构建render tree。
重绘:在回流时,浏览器会使渲染树中受到影响的部分失效,重新构造这部分的渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,这就是重绘。
当render tree中的一些元素需要更新属性而这些属性只是影响元素的外观,不影响布局,这就叫重绘。
函数节流:指的是一定时间内js方法只执行一次;只允许一个函数在 X 毫秒内执行一次。
<style> body{ height: 5000px; } </style> <body> <script> // 简单的节流函数 function throttle(func,wait,mustRun) { var timeout var startTime = new Date() return function(){ var context = this var args = arguments var curTime = new Date() clearTimeout(timeout) // 如果达到了规定的触发事件,触发函数 if (curTime - startTime >= mustRun) { func.apply(context, args) startTime = curTime }else{ // 没到到触发间隔,重新设定定时器 timeout = setTimeout(func,wait) } } } // 正常的事件 function Scroll(){ console.log('scroll ...'); } // 采用节流函数 // window.addEventListener('scroll',throttle(Scroll,1000,2000)) // 不采用节流 window.addEventListener('scroll',Scroll) </script> </body>
函数防抖:是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次;把多个顺序地调用合并成一次,也就是在一定时间内,规定事件被触发的次数。
<style> body{ height: 2000px; } </style> <body> <script> // 简单的防抖函数 function debounce(func,wait,immediate){ // 声明定时器变量 var timeout return function(){ // 每次触发scroll handler时先清除定时器 clearTimeout(timeout) // 指定 xx 秒后 触发真正想要的操作 timeout = setTimeout(func,wait) } } // 正常的scroll事件 handler function Scroll(){ console.log('scroll ...'); } // 测试 // 采用防抖 // window.addEventListener('scroll',debounce(Scroll,1000)) // 不采用防抖 window.addEventListener('scroll',Scroll) </script> </body>
区别:
HTML和JavaScript交互式通过事件的驱动来实现的,例如鼠标的点击事件,页面的滚动事件等,可以向文档或者文档中的元素添加事件侦听器来预定事件。
什么是事件流?
事件流就是描述从页面中接收事件的顺序,DOM 2级事件流主要包括以下几个阶段
addEventListener是DOM 2级事件新增的指定事件处理程序的操作,这个方法接收3个参数
mouseover:当鼠标移入元素或者子元素都会触发事件,对应的移除事件是mouseout
mouseenter:当鼠标移入元素本身(不包含子元素)会触发事件,不会冒泡,对应的移除事件是mouseleave
前端模块化就是将复杂的文件变成一个个独立的模块,每个模块含有对应的功能;分成独立的模块有利于代码的重用和日后的维护,这样就引来了模块之间的相互依赖。
在JS中,数据类型分为基本数据类型和引用数据类型两种,对于基本数据类型来讲,它的值直接存储在栈内存中,而对于引用类型来说,他在栈内存中仅仅存储了一个引用,真正的数据在堆中存储。
当我们对基本类型的数据操作时,会发生如下情况:
var a = 3
var b = a
b = 5
console.log(a);//3
console.log(b);//5
对于基本数据类型来说,我们将一个基本数据类型赋予a变量,接着将a变量的值赋值给了b,然后我们修改b,可以看到b的值修改了,而a的值没有修改,两个变量使用的都是独立的数据。
当我们堆引用类型的数据操作时,会发生如下情况:
/* 引用数据类型 */
var obj1 = {
a:1,
b:2,
c:3
}
var obj2 = obj1
obj2.a = 5
console.log(obj1.a); //5
console.log(obj2.a);//5
可以看到,两个对象的值全被修改了。
对象是引用类型的值,对于引用类型来说,我们将obj1赋予obj2的时候,我们其实仅仅只是将obj1存储在栈中的引用赋予了obj2,两个对象此时指向的是在堆内存中的同一个数据,所以当我们修改任意一个值的时候,修改的都是堆内存中的数据,而不是引用,所以只要修改了,同样引用的对象的值也发生了改变。
上述的例子就是一个简单的浅拷贝!
对于浅拷贝而言,就是只拷贝对象的引用,而不是深层次的拷贝对象的值,多个对象指向堆内存中的同一个对象,任何一个修改都会使得所有对象的值修改,因为他们公用一条数据。
深拷贝
深拷贝作用在引用类型上,例如:Object,Array
深拷贝不会拷贝引用类型的引用,而是将类型的值全部拷贝一份,形成一个新的引用类型,这样就不会发生引用错乱等问题,使得我们可以多次使用同样的数,而不用担心数据之间会起冲突。
深拷贝的实现
首先使用JSON.stringify()以及JSON.parse()
// 深拷贝的实现
// 1. 乞丐版
var o1 = {
a:1,
b:2,
c:3
}
var o_String = JSON.stringify(o1)
var o2 = JSON.parse(o_String)
o2.a = 5
console.log(o1.a);//1
console.log(o2.a);//5
可以看到没有发生引用问题,修改o2的数据,并不会对o1产生影响,为什么说它是乞丐版的?那是因为用JSON.stringify()以及JSON.parse()
它是不可以拷贝undefined、function、regExp等等类型
使用Object.assign(target,source)
// 2.使用Object.assign(target,source)
var o3 = { a:1, b:2, c:3 }
var o4 = Object.assign({},o3)
o4.b = 5
console.log(o3.b);//2
console.log(o4.b);//5
使用这种方式本身没有问题,但是这个一层对象,如果是多层对象就会出现问题
var o5 = { a:1, b:2, c:[1,2,3] }
var o6 = Object.assign({},o5)
o6.c[0] = 100
console.log(o5.c);// [100, 2, 3]
console.log(o6.c);// [100, 2, 3]
可以看到对于一层对象来说是没有任何问题的,但是如果对象的属性对应的是其他引用类型的数据的话,修改还是有问题
递归拷贝
// 3.递归拷贝 function deepClone(target) { let result // 如果当前拷贝的对象是一个对象的话 if (typeof target === 'object') { // 如果当前对象是一个数组的话 if (Array.isArray(target)) { result = [] for (const i in target) { // 递归克隆数组中的每一项 result.push(deepClone(target[i])) } // 如果当前的值为null的话,直接赋值为null } else if (target === null) { result = null // 如果当前的值是一个正则对象的话,直接赋值 } else if (target.constructor === RegExp) { result = target } else { // 否则为普通对象,直接for in 循环,递归赋值对象的所有值 result = {} for (const i in target) { result[i] = deepClone(target[i]) } } // 如果不是对象的话,就是基本数据类型,直接赋值 } else { result = target } // 返回最终结果 return result } // 测试 let object1 = { a:{ c:/a/, d:undefined, b:null }, b:function(){ console.log(this.a); }, c:[ {a:'c',b:/b/,c:undefined}, 'a', 3 ] } let object2 = deepClone(object1) console.log(object2);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。