HTML
1.标记语言
缩写ML:markup language 标记语言
什么是标记语言?
//文本文件是什么?(官方解释)
标记语言是一种将文本(Text)以及文本相关的其他信息结合起来,展现出关于文档结构和数据处理细节的计算机文字编码。与文本相关的其他信息(包括例如文本的结构和表示信息等)与原来的文本结合在一起,但是使用标记(markup)进行标识。
通俗的讲标记语言就是:将被传递的文本内容和一些标识符(p、div、title...)结合起来,标识符用来表明你这个文本内容是个标题类型的还是段落类型的,然后通过多个标识符的嵌套形成文档结构,便于观察文档结构
<title> 标题内容
<p>信息内容</p>
</title>
ML家族:GML、SGML、HTML、XML、XHTML、HTML5
1.GML:
通用标记语言
由 Charles Goldfarb,Edward Mosher 和 Raymond Lorie 三位大神于1969年和1970年代开发(Goldfarb 使用姓氏的缩写来缩写 GML)。
GML是用来搞IBM的文档组成工具的,也是这个工具的主要组件。但是随着计算机的发展,这种语言已经变得相对落后和单一了,所以才诞生了儿子SGML,来一统世界。
2.SGML:
标准通用标记语言
SGML优点有:高稳定性、高可携性、高完整性。
它的缺点有:高复杂性、费用昂贵。
通俗解释:
(用人话说就是,ISO搞出来的东西稳定性是绝对有保证的,也可以跨平台使用,文档说明也是相当完整的,据说文档多达五百多页。
但是它的缺点也正是因为它的稳定性和完整性催生出了高度复杂的特性,其相对衍生出来的就是高费用性的巨大缺陷。
换句话说,一个人想要接手或者使用它,必须先制定它的DTD(文件格式定义),这个DTD的制定是相当复杂和昂贵的,可以简单的想象一下,每次写一个全新DTD标准的SGML文件都需要为此开发一个解析工具(浏览器)的代价。)
3.HTML:
超文本标记语言
1.0 版本于 1993年6月作为互联网工程工作小组(IETF)工作草案发布。
HTML 经过一系列修订,到现在说的 HTML 一般指 HTML 4.01
和XML为兄弟级别
3.XML:
可扩展标记语言
(被设计用来传输和存储数据。XML很重要,也很容易学习。)
如今的数学标记语言MathML和可缩放矢量图形SVG都是使用的XML作为描述语言。
HTML和它兄弟XML最大的区别就在于它兄弟的标签是可以自己创建的,数量无限多,类似于孙悟空的猴毛,而HTML的标签都是固定的而且数量有限。
4.HTML5:
HTML5 则是 HTML 的第五个修订版
主要的目标是将互联网语义化,以便更好地被人类和机器阅读,并同时提供更好地支持各种媒体的嵌入。
HTML5本身不是技术,它是标准。它所使用的技术早已很成熟。
前端技术圈里通常所说的 HTML5 实际上是HTML与CSS3及JavaScript和浏览器API等的一个组合包。
用一个老公式可以说明问题:HTML5 ≈ HTML + CSS3 + JavaScript + 浏览器API
//特别需要注意的是,某些不懂技术的人嘴里说出来的所谓的H5,指的是在移动端上落地页或营销页。这两者千万要区分开。
4.XHTML:
可扩展超文本标记语言
表达方式和HTML其实类似,但是比HTML更严格。
XHTML1.1为XHTML最后的独立标准,2.0止于草案阶段。
因为HTML5的出现,目前XHTML在业界仍然处于非主流的尴尬地位。或许对于XML来说HTML5就是别人家的小孩。
HTML和HTML5的区别
文档类型声明写法上的区别:
HTML的文档类型复杂:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
HTML4的文档类型:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
HTML5 采用一种非常简短、没有版本的文档类型:
<!doctype html>
由上面可以看到,在文档声明上,HTML的声明代码很长很复杂,而HTML5的声明更为简单,方便记忆,所以HTML5要比HTML更有利于程序员的快速阅读和开发。
为什么HTML5文档类型的声明写法简单?
HTML5只是一个标准,HTML5不基于SGML,因此不需要对DTD进行引用,但是需要DOCTYPE来规范浏览器的行为(让浏览器按照他们应该的方式来运行)而HTML4.01基于SGML,所以需要对DTD进行引用,才能告知浏览器文档所使用的文档类型。
语义结构上的区别
HTML4.0:
没有体现结构语义化的标签,通常都是这样来命名的<div id="header"></div>,这样表示网站的头部。
HTML5:
HTML5则增加了很多语义化的标签,比如:<header> 、<nav>、<article>、<aside>、<footer>等,使代码结构清晰,更加具有可读性。
声明文档类型的作用
文档声明是为了告诉浏览器,我们写的HTML文档当前使用什么版本的HTML来写的,这样浏览器才能按照我们声明的版本来正确的解析。
严格模式、混乱模式、DTD
严格模式:
又称为标准模式,指浏览器按照W3C标准解析代码;
混乱模式:
又称怪异模式、兼容模式,是指浏览器用自己的方式解析代码.混杂模式通常模拟老式浏览器的行为,以防止老站点无法工作;
执行严格模式混乱模式的条件:DTD
网页中的DTD,直接影响到使用的是严格模式还是浏览模式,
//DTD类型是一套关于标记符的语法规则。
简而言之,DTD就是用来约束XML文档的,使其在一定的规范下使用
有三种类型:
1、严格版本(S)
2、过度版本(T)
3、基于框架的HTML文档(F)
根据DOCTYPE的存在与否以及使用哪种DTD类型来选择要使用的呈现模式:
//严格模式(标准模式):
1、xhtml、html4.01文档中包含形式完整的DOCTYPE,那么他一般是以标准模式呈现。
2、XHTML、HTML4.01文档包含过度DTD和URI的DOCTYPE以标准模式呈现。
//混杂模式:
1、XHTML、HTML4.01文档只包含过度DTD的DOCTYPE以混杂模式呈现。
2、DOCTYPE不存在或形式不正确会以混杂模式呈现。
//HTML5 没有 DTD ,因此也就没有严格模式与混杂模式的区别,HTML5 有相对宽松的语法,实现时,已经尽可能大的实现了向后兼容
总的来说,严格模式让各个浏览器统一执行一套规范.兼容模式保证了旧网站的正常运行。
2.字符编码
什么是字符编码
(人类语言转化为计算机语言,方便计算机读取)
计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理。
最早的计算机在设计时采用8个比特(bit)作为一个字节(byte)
所以,一个字节能表示的最大的整数就是255(二进制11111111=十进制255),如果要表示更大的整数,就必须用更多的字节。
比如两个字节可以表示的最大整数是65535,4个字节可以表示的最大整数是4294967295。
三种常见字符编码:ASCII、Unicode和UTF-8的关系
是什么?
为什么出现?
应用场景?
8比特表示一个字节,通过一个字节排列表示不同的人类语言,显然不够,所以字节类越多越能表示更多的人类语言,Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。
强调一下,unicode是一种编码方式,和ascii是同一个概念,而UTF-8,UTF-16等是一种存储方式,在存储和传输上节约空间、提高性能的一种编码形式。
3.如何使用 HTML5 嵌入音频和视频(媒体标签)
HTML5 使用 audio 和 video 元素来嵌入音频和视频内容。
支持这两个标签的浏览器有这些:IE9+、Firefox 3.5+、Safari 4+、Opera 10.5+、Chrome、iOS 版的 Safari 和 Android 版的 Webkit。
另外还提供了与这两个标签相关的 JavaScript API,这样就可以创建我们自己的音视频控件咯:
<!-- 嵌入视频 -->
//HTML5 支持 MP4、WebM 和 Ogg 格式的视频
<video id="player"
src="xxx.ogg"//这两个标签,都必须包含 src 属性,即要加载的媒体文件地址。
poster="mymovie.jpg"//poster 属性是在加载视频期间会显示的图像。
width="300" height="200">//width 和 height 属性是指定视频播放器的大小。
Video player not available.//位于开始和结束标签之间的内容是后备内容,即当浏览器不支持这两个标签时会显示这些内容。
</video>
<!-- 嵌入音频 -->
//HTML5 支持 MP3、Wav 和 Ogg 格式的音频
<audio src="xxx.mp3" id="myAudio">Audio player not available.</audio>
因为不是所有的浏览器都支持所有的媒体格式,所以可以指定不同的媒体来源。这时会用到 `` 标签:
<!-- 嵌入视频 -->
<video id="player">
<source src="xx.webm" type="video/webm; codecs='vp8, vorbis'">
<source src="xx.ogv" type="video/ogg; codecs='theora, vorbis'">
Video player not available.
</video>
<!-- 嵌入音频 -->
<audio id="myAudio">
<source src="xx.ogg" type="audio/ogg">
<source src="xx.mp3" type="audio/mpeg">
Audio player not available.</audio>
4.除了audio和video,HTML5还有哪些媒体标签?
标签定义嵌入的内容,比如插件。
<embed type="video/quicktime" src="Fishing.mov">
标签定义多个数据源很有用。
<video width="450" height="340" controls>
<source src="jamshed.mp4" type="video/mp4">
<source src="jamshed.ogg" type="video/ogg">
</video>
标签为诸如video元素之类的媒介规定外部文本轨道。
用于规定字幕文件或者其他包含文本的文件,当媒介播放时,这些文件是可见的。
<video width="450" height="340" controls>
<source src="jamshed.mp4" type="video/mp4">
<source src="jamshed.ogg" type="video/ogg">
<track kind="subtitles" label="English" src="jamshed.mp4">
<track kind="subtitles" label="Arabic" src="jamshed.ogg">
</video>
————————————————
版权声明:本文为CSDN博主「iteye_1217」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/iteye_1217/article/details/82678635
5.HTML5 Canvas元素有什么用?
Canvas元素用于在网页上绘制图形,该元素标签强大之处在于直接在HTML上进行图形操作(通过在html设置宽高、虚线、旋转、坐标等属性,来改变网页渲染的图像形状)
设置绘制区域:
<canvas id="tutorial" width="300" height="300"></canvas>
//<canvas>看起来和<img>标签一样,只是 <canvas> 只有两个可选的属性 width、heigth 属性,而没有 src、alt 属性。
//如果不给<canvas>设置widht、height属性时,则默认 width为300、height为150,单位都是px。
//也可以使用css属性来设置宽高,但是如宽高属性和初始比例不一致,他会出现扭曲。所以,建议永远不要使用css属性来设置<canvas>的宽高。
浏览器不支持canvas标签时,设置替换的内容
由于某些较老的浏览器(尤其是IE9之前的IE浏览器)或者浏览器不支持HTML元素<canvas>,在这些浏览器上你应该设置一些东西来替换canvas标签。
支持<canvas>的浏览器会只渲染<canvas>标签,而忽略其中的替代内容。
不支持 <canvas> 的浏览器则 会直接渲染替代内容。
文字替换:
<canvas>
你的浏览器不支持canvas,请升级你的浏览器
</canvas>
图片替换:
<canvas>
<img src="./美女.jpg" alt="">
</canvas>
案例展示:绘制两个长方形:
<html>
<head>
<title>Canvas tutorial</title>
//css样式
<style type="text/css">
canvas {
border: 1px solid black; //绘制范围区域边框
}
</style>
</head>
<body>
//设置绘制标签,区域
<canvas id="tutorial" width="300" height="300"></canvas>
</body>
//js画图形
<script type="text/javascript">
function draw(){
//检测是否支持2d绘制
var canvas = document.getElementById('tutorial');
if(!canvas.getContext) return;//不支持就返回
var ctx = canvas.getContext("2d");
//检测完毕
//下面的代码就是开始绘制图像的
ctx.fillStyle = "rgb(200,0,0)";
//绘制矩形:距离坐标
ctx.fillRect (10, 10, 55, 50);
//颜色
ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
ctx.fillRect (30, 30, 55, 50);
}
draw();
</script>
</html>
6.HTML5存储类型有什么区别?
HTML5能够本地存储数据,在之前都是使用cookies的
HTML5提供了下面两种本地存储方案:
1.localStorage用于持久化的本地存储,数据永远不会过期,关闭浏览器也不会丢失。
2.sessionStorage同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不 是一种持久化的本地存储,仅仅是会话级别的存储。
(会话级别储存:关闭页面后,数据随之销毁)
//将服务器返回的token储存到本地页面的sessionStorage:
window.sessionStorage.setItem("token",res.data.token) //键值对形式:属性名,属性值
//在哪里查看被保存的sessionStorage?F12--Application
浅谈session,cookie,sessionStorage,localStorage的区别及应用场景
7.HTML5新增表单类型
email: 提交表单时检测值是否是一个电子邮件格式
url: 提交表单时检测值是否是一个url格式
date: 年-月-日格式的控件
time: 时:分格式的控件
datetime: 年-月-日 时:分 格式的控件(UTC时间)
datetime-local: 年-月-日 时:分 格式的控件(本地时间)
month: 年-月格式的控件
week: 年-周数格式的控件
number: 数字输入框
<input type="number" name="" id="" value="60" max="100" min="0" />
range: 选择区域
<input type="range" name="" id="" value="60" max="100" min="0" />
tel: 电话输入框
search: 用于搜索
color: 调用系统选色器
8.与4比较,HTML5中废弃的标签
CSS
1.less
为什么出现less?
因为css虽然简单,但是写css时结构没有逻辑性,不便于维护
CSS 需要书写大量看似没有逻辑的代码,不方便维护及扩展,不利于复用,尤其对于非前端开发工程师来讲,往往会因为缺少 CSS 编写经验而很难写出组织良好且易于维护的 CSS 代码,造成这些困难的很大原因源于 CSS 是一门非程序式语言,没有变量、函数、SCOPE(作用域)等概念。
和css相比下,css的语法非常简单,而且对开发者来说要求比较低,比较合适小白者,但是遇到有些问题,比如没有这种变量、函数等等,的确还不如less的扩展性,需要写大量的代码,但是看眼中的确没有逻辑的代码,CSS冗余度是比较高的。不方便维护,不利于复用,而且没有计算的能力。
less的出现是为了解决代码维护性和复用性的问题
less是什么?
它是一门CSS预处理(升级版),扩充了CSS,增加了诸如变量、混合(mixin)、函数等功能,让 CSS 更易维护、方便制作主题、扩充,Less 也可以运行在 Node 或浏览器端。
总结:让CSS更具维护性、主题性、扩展性!
less的编译模式
因为less不像css一样,直接被浏览器解析渲染,所以需要通过编译软件(我推荐koala)进行编译。
koala有两种常用编译模式,分别为normal与compress。
(1)normal(默认):
编译成css格式,不压缩为一行。(利于更新和维护)
(2)compress:
编译成压缩的CSS格式,只有一行,紧凑贴紧,对浏览器更加友好,且大小相比未压缩要小一些(推荐发布使用)
less和css写法逻辑上的区别
相比一下,还是感觉less语句的代码比较舒服,以上代码内容就是叫嵌套写法,这样的话大大减少了代码量,less代码看起来更加清晰。
less变量的延迟加载特性
延时加载特性 (1)变量不需要预先声明 (2)变量可以在任意位置出现
header{
background:url(@bg-img);
}
@bg-img:"路径1";
@bg-img:"路径2";
@bg-img:"路径3";
//结果为:background: url("路径3");
less变量
用法一:
命名语法:@变量名:值
使用语法:@变量名
//定义变量(全局变量)
//一定要注意定义在全局变量,定义在花括号{}里的是局部变量,其他地方调用不到局部变量的,无法在多个地方复用
//变量的优点是:节省代码量,不需要在很多地方(需要这个样式的地方)写同样的代码,只需要简单写变量名
@COLOR:rgb(255,0,0);
@WIDTH:200px;
header{
background:@COLOR;
}
div{
background:@COLOR;
padding:@WIDTH;
}
用法二:
命名语法:@变量名:属性名
使用语法:@{变量名}:值
//定义变量(属性名)
//嫌弃background-image太长,那么用自己设置的简洁的变量名代替
@bg-img:background-image;
div{
@{bg-img}:路径;
}
用法三:
命名语法:@变量名:类名
使用语法:@{变量名}-附加类名{}
//定义
@demo:newClass;
// "-new"在类名基础上,新的类名 newClass-new
.@{demo}-new{
@bg:rgb(0,0,0);
background:@bg;
}
//div使用此类名
<div class="newClass-new">
<p>demo</p>
</div>
变量的覆盖性
less会从当前作用域中从下往上搜索,这个行为类似于css的定义:始终使用最后定义的属性值!
当然,定义同一变量名称(名字)两次或多次后,less只会选择最后定义的!
//
@bg-img:"路径1";
@bg-img:"路径2";
@bg-img:"路径3";
header{
background:url(@bg-img);
}
//结果为:background: url("路径3");
引入外部less文件
将变量储存在外部less文件,并赋值样式。然后在其他文件需要调用外部文件里的变量,就可以引入这个less文件
//main.less外部文件
@baby:300px;
//index.less文件中引入
//16.引入
@import "../main";//引入main.less文件
.contain-qq{
width:@baby;
}
2.如何将div盒子防止网页正中间?
div盒子在网页居中:放置网页正中间
//绝对定位、相对位移
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
3.css居中的所有方法:
一、水平居中:就是x轴上的取中位置
方法总结:
text-align、flex布局的属性、margin的auto属性、position:absolute
子行内元素
如果被设置元素为文本、图片等行内元素时,水平居中是通过给父元素设置 text-align:center来实现的。
.parent{ //让儿子居中,给父亲设置
text-align: center;
}
具有宽度设置的块级元素
我们可以通过将一个块级元素的margin-left和margin-right同时设置为auto来使其居中。(注意:此时元素必须定义有width,否则将填满宽度,谈不上水平居中。)通常由以下简写来定义:
.myself {
width:100px
margin: 0 auto;
}
多个块级元素
两种方法:各有优缺
1.转化成inline-block后,成为行内元素,对父级设置text-align:center
当设置高度固定时:
<main>
<div>内容1</div>
<div>内容2</div>
<div>内容3</div>
</main>
<style>
main{
text-align:center;
}
div{
display:inline-block;
}
</style>
//缺点在于:不论高度为多少,对齐方式都是根据内容的基线进行对齐,高度不设置根据内容时,对齐就以低对齐,高度设置固定时对其就是根据文字内容的基线对齐
2.flex布局:子元素行内元素,父级是块,使用flex弹性布局和justify:center
justify:cengter:弹性项目居中紧挨着填充。(如果剩余的自由空间是负的,则弹性项目将在xy两个方向上同时溢出)。
<main>
<div>内容1</div>
<div>内容2</div>
<div>内容3</div>
</main>
<style>
main{
display: flex;
justify-content: center;
}
div{
display:inline-block;
}
</style>
优点是:能将元素自动拉伸溢出。缺点就是你可能不需要这种拉伸
二、垂直居中
方法总结:
行内: padding手动设置距离、auto自动分配距离 、line-height等于height
块级:
高度已知/未知:padding:absolute、flex
行内元素:单行高度范围的行内元素垂直居中
实现的本质就是人为计算上下间距,使其相等。
设置padding:top和padding:bottom
行内元素:文字在区域高度居中时:
使用padding的auto属性,只需要设置padding:20px即可完成上下间距的自动分配相等距离,左右距离为规定的20px
在某些情况当padding不便于计算,并且文字不会换行时,有一个技巧:当line-height与height相等时,文字垂直居中。
.myself {
height: 100px;
line-height: 100px;
white-space: nowrap;
}
行内元素:多行文字在框中垂直居中
使用flexbox
flex-center-vertically {
display: flex;
justify-content: center; //让间距相等居中
flex-direction: column; //纵向排列
height: 400px;
}
//我写css必定会用到他,自此之后摒弃flaot,毕竟float要清楚浮动,在我看来他完全可以替代float,而且最大的好处就是对任何不确定的宽和高,我们都可以让他垂直居中对齐
块级元素
position
高度已知: 因为高度已知了,我们就可以自己计算出上下间距,使用绝对定位position设置具体数值即可
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
height: 100px;
margin-top: -50px; //这步是用来解决是否有外边框border时的情况,抵消掉外边框距离
}
高度未知时:仍然可以使用positiong
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
transform: translateY(-50%); //平移,高度未知时是以元素顶端开始计算的,所以需要以自身大小进行移动自身大小一半
}
flexbox
不需要关注高度设定
.parent {
display: flex;
flex-direction: column;
justify-content: center;
}
三、同时垂直水平居中
宽高固定时:position
.parent {
position: relative;
}
.child {
width: 300px;
height: 100px;
padding: 20px;
position: absolute;
top: 50%;
left: 50%;
margin: -70px 0 0 -170px; //解决外边框的
}
宽高不固定:position
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); //自身平移
}
外能方法:flex
.parent {
display: flex;
justify-content: center;
align-items: center;
}
4.flex布局的justify-content的属性详解
语法:justify-content: flex-start | flex-end | center | space-between | space-around
flex-start:
弹性项目向行头紧挨着填充。这个是默认值。第一个弹性项的main-start外边距边线被放置在该行的main-start边线,而后续弹性项依次平齐摆放。
flex-end:
弹性项目向行尾紧挨着填充。第一个弹性项的main-end外边距边线被放置在该行的main-end边线,而后续弹性项依次平齐摆放。
center:
弹性项目居中紧挨着填充。(如果剩余的自由空间是负的,则弹性项目将在两个方向上同时溢出)。
space-between:
弹性项目平均分布在该行上。如果剩余空间为负或者只有一个弹性项,则该值等同于flex-start。否则,第1个弹性项的外边距和行的main-start边线对齐,而最后1个弹性项的外边距和行的main-end边线对齐,然后剩余的弹性项分布在该行上,相邻项目的间隔相等。
space-around:
弹性项目平均分布在该行上,两边留有一半的间隔空间。如果剩余空间为负或者只有一个弹性项,则该值等同于center。否则,弹性项目沿该行分布,且彼此间隔相等(比如是20px),同时首尾两边和弹性容器之间留有一半的间隔(1/2*20px=10px)。
5.box-sizing: border-box的作用
给输入框加上padding后,左右两边都有距离,外露出来了,是因为没有将盒子尺寸锁定
使用场景和作用
6.输入框密码如何隐藏成黑点显示?
<input type="password"></input>
7.flex布局的align-items
align-items属性可以应用于所有的flex容器,它的作用是设置flex子项在每个flex行的交叉轴上的默认对齐方式。不同取值的效果如下所示:
8.letter-spacing
1.设置文字间距
9.cursor: pointer
//给元素添加的css样式
1.当移动到此元素上时,鼠标指针变成 手 的形状,和放到链接上面的鼠标指针一样
JS
1.js规定了几种语言类型
1.undefined型
何时出现undefined?
1.函数默认return的是undefined
function ret() {
// 默认是返回 undefined
}
2.获取对象不存在的 key
var obj = {}
obj.name
3.获取数组不存在的下标
var aa = []
aa[0] undefined
4.声明变量,不初始化值var foo;
2.null型
null 表示的是:“定义了但是为空”。
所以在未确定赋具体什么值给它时,就能先复制null来代替。
Null 类型也只有一个值,就是 null,它的语义表示空值
3.Boolean型
两个值:true false
4.number型
经典面试问题:0.1+0.2!=0.3 ?
5.string型
字符串
6.symbol
Symbol是唯一的数据结构, 只要你声明了Symbol, 那么就是唯一的了.
1.直接声明
let ck = Symbol('ck') // 后面的‘ck’不是Symbol存储的值, 只是为了区别不同的Symbol的描述.
let kb = Symbol('kb')
console.log(ck);
console.log(kb);
console.log(ck === kb) // false
// 即使后面的描述是一样的, 两个返回的也是false
let ck2 = Symbol('ck2')
let ck3 = Symbol('ck2')
console.log(ck2 === ck3) // false
try{}catch(e){}的理解
js如果出现错误,浏览器则会在console面板中打印出错误,那么我们为什么还要使用try catch呢?
结论:为了在js出现错误的时候,把异常捕获掉,这样程序仍能正常运行下去
a.如下,如果我们这样写:
console.log(i);
var a = 6;
console.log(++a);
因为i未定义,出现错误,那么js就卡在这里了,我们预期的输出a的结果也不执行了。
b.如果,我们使用try catch:
try {
console.log(i);
}catch(e) {
console.log(e)
}
var a = 6;
console.log(++a);
那么,i未定义的错误被捕获掉了,程序仍能继续运行下去,最后输出a的结果是7
0.1 + 0.2 != 0.3问题
人话:
由于JS是使用浮点数来计算,会产生计算精度问题,0.1和0.2都是一个近似值,两个近似值相加得出的就是不精确的值。
回答:
JavaScript 使用 Number 类型来表示数字(整数或浮点数),遵循 IEEE 754 标准
通过 64 位来表示一个数字(1 + 11 + 52)
1 符号位s:0 表示正数,1 表示负数 s
11 指数位(e)
52 尾数,小数部分(即有效数字)
最大安全数字:Number.MAX_SAFE_INTEGER = Math.pow(2, 53) - 1,转换成整数就是 16 位,所以 0.1 === 0.1,是因为通过 toPrecision(16) 去有效位之后,两者是相等的。
在两数相加时,会先转换成二进制,0.1 和 0.2 转换成二进制的时候尾数会发生无限循环,然后进行对阶运算,JS 引擎对二进制进行截断,所以造成精度丢失。
解决的最常用的方法就是将浮点数转化成整数计算。
因为整数是可以精确表示并计算的。
function formatFloat (num1, num2) {
var baseNum, baseNum1, baseNum2;
//计算需要划算成整数需要乘以的倍数:10*次方
try {
baseNum1 = num1.toString().split(".")[1].length;
} catch (e) {
baseNum1 = 0;
}
try {
baseNum2 = num2.toString().split(".")[1].length;
} catch (e) {
baseNum2 = 0;
}
//划算成整数后,使用Math.max获取这个字符串200101000里的最大数字2,开始计算
baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
return (num1 * baseNum + num2 * baseNum) / baseNum;
};
console.log(formatFloat(0.1,0.2))
JS的整数是如何表示的?
通过 Number 类型来表示,遵循 IEEE754 标准,通过 64 位来表示一个数字,(1 + 11 + 52),最大安全数字是 Math.pow(2, 53) - 1,对于 16 位十进制。(符号位 + 指数位 + 小数部分有效位)
Number() 的存储空间是多大?如果后台发送了一个超过最大自己的数字怎么办
Math.pow(2, 53) ,53 为有效数字,会发生截断,等于 JS 能支持的最大数字。
2.原型prototype
为什么出现prototype?
function Star() {
this.sing = function () {
console.log('我爱唱歌');
}
}
let stu1 = new Star();//new个实例对象
let stu2 = new Star();//new个实例对象
stu1.sing();//调用函数sing//输出:我爱唱歌
stu2.sing();//调用函数sing//输出:我爱唱歌
console.log(stu1.sing === stu2.sing);//输出:false
//两个实例对象的方法并不是相同的函数,虽然输出结果一样
很明显,stu1 和 stu2 指向的不是一个地方。
所以 在构造函数上通过this来添加方法的方式来生成实例,每次生成实例,都是新开辟一个内存空间存方法。
但是我们需要两个实例对象使用的是一个方法,但是你每次都是开辟两个新的函数,输出一样的结果,这样会导致内存的极大浪费,从而影响性能。
所以我们需要一个东西,让实例对象都调用的是一个函数sing,这个东西就是原型
原型是什么?
function Star(name) {
this.name = name;
}
Star.prototype.sing = function () {
console.log('我爱唱歌', this.name);
};
let stu1 = new Star('小红');
let stu2 = new Star('小蓝');
stu1.sing();//我爱唱歌 小红
stu2.sing();//我爱唱歌 小蓝
console.log(stu1.sing === stu2.sing);//true
//Father.prototype 就是原型,它是一个对象,我们也称它为原型对象。
原型的作用:
原型的作用,就是共享方法。
我们通过 Father.prototype.method 可以共享方法,不会反应开辟空间存储方法。
//定义构造函数的规则:公共属性定义到构造函数里面,公共方法我们放到原型对象身上。
//原型中this的指向是实例。
3.new个新对象的过程,发生了什么?
通过构造函数构建一个对象:son()
1.构建构造函数Father(){}
function Father(name) {
this.name = name;
}
2.创建实例对象son
let son = new Father('Lisa');
console.log(son); //输出:Father {name: "Lisa"}
此时,son就是一个新对象。
new的内部过程:
(1) 创建一个空对象 son {}
(2) 为 son 准备原型链连接:son.__proto__ = Father.prototype(son的原型指向构造函数的原型)
(3) 重新绑定this,使构造函数的this指向新对象Father.call(this)(this指向改变:指向son)
(4) 为新对象属性赋值son.name
(5) 返回this (return this),此时的新对象就拥有了构造函数的方法和属性了
4.原型链?
定义:
简单理解就是:
原型组成的链,对象的__proto__是它的原型,而原型也是一个对象,也有__proto__属性,原型的__proto__又是原型的原型,就这样可以一直通过__proto__想上找,这就是原型链,
当向上找找到Object.prototype原型链的顶端,所有对象从它继承了包括toString等等方法和属性。
JS就是通过这个链条来实现的继承。
按照JS引擎的分析方式,在访问一个实例的属性或方法的时候,先在实例本身中找,如果没找到就去它的原型中找,还没找到就再往上找,直到找到。
原型链查找方法的流程:
function Star(name) {
this.name = name;
(1)首先看实例对象身上是否有dance方法,如果有,则执行对象身上的方法
this.dance = function () {
console.log(this.name + '1');
}
}
(2)如果没有dance方法,就去构造函数原型对象prototype身上去查找dance这个方法。
Star.prototype.dance = function () {
console.log(this.name + '2');
};
(3)如果再没有dance方法,就去Object原型对象prototype身上去查找dance这个方法。
Object.prototype.dance = function () {
console.log(this.name + '3');
};
(4)如果再没有,则会报错。
let obj = new Star('小红');
obj.dance();
5.原型链图解析
记住一个关键点:外物皆对象,对象皆有原型,原型指向原型
6.promise使用
本质(promise源码)
promise本质是个类/构造函数,我们使用时先new一个实例对象,然后输入形参resolve、reject(这两个形参是两个函数),之后条件调节判断执行哪个函数
本质解读
官方文档
是什么promise是一种写法规定,为了将复杂的逻辑代码写成好看、好操作的代码写法
用于解决什么
解决函数嵌套写法问题(链式函数):
函数1里面包裹函数2,函数2包裹函数3,递推。就构成了回调地狱(函数2需要使用函数1的结果进行操作,函数3需要使用函数2的结果进行操作)
//回调地狱的缺点:
代码臃肿。
可读性差。
耦合度过高,可维护性差。
代码复用性差。
容易滋生 bug。
只能在回调里处理异常。
写法:
new Promise(请求1)
.then(请求2(请求结果1))
.then(请求3(请求结果2))
.then(请求4(请求结果3))
.then(请求5(请求结果4))
.catch(处理异常(异常信息))
返回值理解:
promise函数都会返回一个promise对象,可以用then进行操作
对请求结果1的后续操作是个异步任务(事件)的话就需要.then()=>{return new Promise(‘命令’)}(继续调用后续函数对结果1进行操作)
对请求结果1的后续操作是个同步任务的话就直接.then()=>{return (‘命令’)}(直接输出命令)
计算面试题:
7.类
1.本质由来
JavaScript 语言中,生成实例对象的传统方法是通过构造函数。下面是一个例子。
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
上面这种写法跟传统的面向对象语言(比如 C++ 和 Java)差异很大,很容易让新学习这门语言的程序员感到困惑。
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用 ES6 的class改写,就是下面这样。类是es6新写法=es5的构造函数
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
//constructor()方法,这就是构造方法
//this本身指向实例对象
//
2.类的方法都定义在prototype上
构造函数的prototype属性,在 ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
//上面代码中,constructor()、toString()、toValue()这三个方法,其实都是定义在Point.prototype上面。
3.constructor方法:constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。
一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
4.ES6中类没有变量提升:通过构造函数创建实例,是可以变量提升的。 es6中的类,必须先有类,才可以实例化。
5.向类中添加方法:通过Object.assign,在原型上追加方法。
class Father{
constructor(name){
this.name = name;
}
sing(){
return this.name;
}
}
//在原型上追加方法
Object.assign(Father.prototype,{
dance(){
return '我爱跳舞';
}
});
let red = new Father('小红');
let green = new Father('小绿');
console.log(red.dance());//我爱跳舞
console.log(red.dance === green.dance); //true
8.防抖
防抖:吟唱技能中
节流:冷却中
防抖分为:立即执行和未立即执行防抖
应用场景:
1.搜索框连续输入内容:
逻辑:当键盘输入一个字符就会进行请求搜索列表数据(keyup键盘抬起事件实现)
不设置防抖的效果:每次输入一个字符都会重新请求数据并显示搜索列表数据
设置防抖策略后:防抖策略让其在输入完成的时候才请求搜索列表数据,减少请求次数。
2.按钮多次点击事件:
如果给一个按钮绑定了表单提交的post事件,但是用户有些时候在网络情况极差的情况下多次点击按钮造成表单重复提交,如何防止多次提交的发生?
3.拖拽元素事件:
如果实现了dom拖拽功能,但是在绑定拖拽事件的时候发现每当元素稍微移动一点便触发了大量的回调函数,导致浏览器直接卡死,这个时候怎么办?
防抖源码解析:
//构造debounce函数(形参fn:函数,形参wait:延迟触发时间)
function debounce(fn, wait) {
var timer = null;
return function () {
//this指向改变
var context = this
var args = arguments
//如果存在定时器,就清除定时器的当前累计等待时间,重新归零计时
//此时的timer使用了闭包:调用函数外的timer
if (timer) {
clearTimeout(timer);
timer = null;
}
//不存在定时器,就设置一个定时器事件:等待一段时间后,调用输出函数fn
timer = setTimeout(function () {
fn.apply(context, args) //args:arguments 对象包含了传给函数的所有实参
}, wait)
}
}
//当定时器计时完成后,再触发事件fn
var fn = function () {
console.log('boom') //输出boom
}
// 调用防抖函数
debounce(fn,500)
如何在VUE中使用防抖函数
两种方法:封装utils工具、封装组件
封装utils工具
//utils.js文件
//1.构件防抖函数
//func=function
//...args=剩余参数
export function debouce(func,delay){
let timer=null;
return function(...args) {
if(timer) {
// 如果上次的定时器还存在,则清除。重新等待时间
clearTimeout(timer);
}
timer=setTimeout(()=> {
//里边的闭包的this必须保持和callback保持一致。确保使用ok
func(...args);
}, delay)
}
}
//2.父组件调用防抖函数
import debounce from './utils'//引入
//4.调用防抖函数
created(){
//传入实参:箭头函数和延迟时间100
this.getThemeTopY = debouce( () => {
console.log(‘防抖函数执行’)
}, 100)
}
//3.调用函数getThemeTopY()
methods:{
getThemeTopY()
}
9.节流
节流分为:时间戳和定时器两种节流法
应用场景:
1.鼠标不断点击不断触发事件,节流让其在设定的时间段内多次点击,但只触发一次事件
2.懒加载要监听滚动条的位置,但不必每次滚动都触发监听事件,降低监听频率,不浪费cpu资源
时间戳法
//通过时间戳比较来确定是否执行事件
function throttle(func,time){
var lastTime = 0;
return function(){
var newTime = +new Date();//获取当前时间戳
//判断条件:当前时间戳减去上一次的时间戳大于冷却时间,那么就可以执行事件,并将当前时间作为lastTime,用于下一次比较判断
if(newTime - lastTime >= time){
func.apply(this,arguments);
lastTime = newTime;
}
}
}
定时器法
function thottle(func,time){
var timer = null;
return function(){
var _this = this;//让this仍然指向原来的this,不改变指向(仍然指向vue实例)
var arg = arguments;//将传入的实参储存进变量arg
//如果timer不存在=事件冷却完毕,可以执行事件,反之timer被赋值为定时器函数,那么就是在冷却中
if(!timer){
timer = SetTimeout(function(){
func.apply(_this,arg);
timer = null; //timer只是变量,直接赋值为null并不能停止计时器
},time);
}
}
}
10.setTimeout执行流程
人话总结:自上往下解析执行代码,遇到setTimeout函数自动忽略,继续执行完全部的在返回来执行setTimeout函数里的函数式。
console.log('script start') //1. 打印 script start
setTimeout(function(){
console.log('settimeout') // 4. 打印 settimeout
}) // 2. 调用 setTimeout 函数,并定义其完成后执行的回调函数
console.log('script end') //3. 打印 script start
// 输出顺序:script start->script end->settimeout
11.Promise执行流程
Promise本身是同步的立即执行函数, 当在executor中执行resolve或者reject的时候, 此时是异步操作, 会先执行then/catch等,当主栈完成后,才会去调用resolve/reject中存放的方法执行,打印p的时候,是打印的返回结果,一个Promise实例。
人话:执行同步任务(1),Promise本身自己的函数式是立即执行的(2、3),当有内部有resolve()时,会将resolve.then放置异步任务中,执行完同步任务(4),在将异步任务添加到同步任务底端开始执行(5),最后执行定时器的回调函数(6)(定时器的执行流程和定时器设定的延迟时间无关)
console.log('script start') 1
let promise1 = new Promise(function (resolve) {
console.log('promise1') 2
resolve()
console.log('promise1 end') 3
}).then(function () {
console.log('promise2') 5
})
setTimeout(function(){
console.log('settimeout') 6
})
console.log('script end') 4
// 输出顺序: script start->promise1->promise1 end->script end->promise2->settimeout
12.async和await
1.这两个要一起使用
2.使用场景:当异步函数在执行时,先等,让异步执行完毕再对异步函数结果执行后续函数式
3.这两个都相当于修饰符,async修饰后面的这个函数是个异步函数。await修饰的是等待的意思,异步函数执行遇到await时就会暂停并返回去执行完毕异步函数,然后才开始执行await后面的函数体
4.async-await是promise和generator的语法糖。只是为了让我们书写代码时更加流畅,当然也增强了代码的可读性。简单来说:async-await 是建立在 promise机制之上的,并不能取代其地位。
async
async是一个加在函数前的修饰符,被async定义的函数会默认返回一个Promise对象resolve的值。
因此对async函数可以直接then,返回值就是then方法传入的函数。
await
await 也是一个修饰符,只能放在async定义的函数内。可以理解为等待。
await 修饰的如果是Promise对象:可以获取Promise中返回的内容(resolve或reject的参数),且取到值后语句才会往下执行;
如果不是Promise对象:把这个非promise的东西当做await表达式的结果。
案例:登录页面的密码账号post到服务器进行账号验证是否正确
methods: {
//点击登录事件:提交账号密码到服务器进行验证
//post提交后是个异步函数,需要等待服务器完成验证后再进行console输出操作,不然会跳过验证过程直接输出res,造成输出结果为一个promise函数
//这里async声明了后面的函数是个异步函数,await用来等待
login () {
this.$refs.loginFormRef.validate( async (valid) => {
if(!valid) return
const res= await this.$http.post('login',this.loginForm)
console.log(res)
})
},
用案例解释:其实就是和异步的执行流程有关,改变了异步执行流程,让其和同步任务一样按顺序执行
13.ES6的解构赋值
什么是解构赋值?
//以前的赋值是:等号后直接根实参值
let a = 1;
let b = 2;
let c = 3;
//ES6的解构赋值:
ES6 可以从数组/对象中提取值,按照对应关系,对变量赋值。左边的变量就会被赋予对应的实值。
let {data:res}={data:'18'};
console.log(res);//输出为18
14.模块化和组件化开发
组件化就是调用组件和复用组件(在于代码复用,将重复利用的代码编写成组)
模块化就是导出export组件,引入import组件
模块化是虚词,是单个组件/多个组件实现的一个功能,这个功能放在一个文件下,这个文件就是模块
模块化就是把单独的一个功能(可以是调用组件实现功能,也可以是纯代码编写功能)封装到一个模块(文件)中,模块之间相互隔离,但是可以通过特定的接口公开内部成员,也可以依赖别的模块 数组的解构赋值
//从数组中提取值,按照对应位置,对变量赋值。只要等号两边的模式相同,左边的变量就会被赋予对应的值。
//对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
//
let [a, b, c] = [1, 2, 3];
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
let [x, , y] = [1, 2, 3];
x // 1
y // 3
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
对象的解构赋值
//对象的解构与数组有一个重要的不同。
数组的元素是按次序排列的,变量的取值由它的位置决定;
而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
//
let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined