3.解决垂直外边距塌陷?
- 给父元素设置边框
- 给父元素设置overflow:hidden;
- 让子元素脱标(浮动| 定位)
4.CSS三大特性?
层叠性、继承性、优先级
5.隐藏元素的方式?
- opacity:设置一个元素的透明度
.hide {opacity: 0;}
- visibility:设置一个元素可见\不可见.hide {visibility: hidden}
.hide {visibility: hidden;}
- display:设置显示与隐藏(隐藏的元素不占位置)
.hide {display: none;}
- position:设置元素位置
.hide {
position: absolute;
top: -9999px;
left: -9999px;
}
- clip-path:
.hide {
clip-path: polygon(0px 0px, 0px 0px, 0px 0px, 0px 0px);
}
6.块元素、行内元素、行内块元素有哪些?有什么特点?
- 块元素——div、p、h1-h6、ul、ol、dl、li
特点:
- 所有的块级元素默认都是独占一行显示
- 如果一个块级元素没有设置宽度,那么其宽度等于其父元素的宽度
- 可以给块级元素设置宽度和高度
- 行内元素——span、a、 font、strong、em、i、ins、u...
特点:
- 所有的行内元素都在一行上显示.
- 行内元素的宽度和高度是其内容撑开的范围大小
- 行内元素默认不能设置宽度和高度
- 行内块——img、input
特点:
- 元素在一行上显示
- 可以给行内块元素设置宽度和高度
7.盒模型的组成部分?盒模型实际大小?
盒模型由内容区域、内边距、边框、外边距四部分组成。
盒模型实际大小由内容区域、内边距、边框三部分组成。
- 如果对盒子不进行设置(或者设置为box-sizing: content-box; ),那么给盒子设置的width和height属性就等于盒模型内容区域大小
- 如果对盒子设置 box-sizing: border-box; 那么给盒子设置的width和height属性就等于盒模型的实际大小(包括内容区域、内边距、边框)
8.选择器优先级排序?
浏览器默认属性 < 继承自父元素的属性 < 通配符选择器 < 标签选择器 < 类选择器 < 结构伪类选择器 < id选择器 < 行内样式 < !important
9.attribute和property有什么区别?
- Attribute是HTML标签上的属性,它的值只能是字符串。Attribute就是dom节点自带的属性,例如html中常用的id、class、title、align等。
- property是DOM中的属性,是JavaScript中的对象。而Property是这个DOM元素作为对象,其附加的内容,例如childNodes、firstChild等。
<div id="div1" class="divClass" title="divTitle" title1="divTitle1"></div>
var in1=document.getElementById("div1");
console.log(in1);
参照以上代码,对于id为div1的div,它的property内容如下:(部分)
可以发现有一个名为“attributes”的属性,类型是NamedNodeMap,同时有“id”和“className”、”title“等基本的属性,但没有“titles”这个自定义的属性。可以看出,标签中的属性,“id”、“className”、”title“会在in1上创建,而“titles”不会被创建。这是由于,每一个DOM对象都会有它默认的基本属性,而在创建的时候,它只会创建这些基本属性,我们在TAG标签中自定义的属性是不会直接放到DOM中的。
自定义的“title1”被放在了attributes这个对象里,这个对象按顺序记录了我们在TAG中定义的属性和属性的数量。从这里就可以看出,attributes是属于property的一个子集。
10.CSS布局问题?怎么实现三列布局?如果中间是自适应又该怎么做?
- 使用浮动布局来实现
- 左侧元素与右侧元素优先渲染,分别向左和向右浮动
- 中间元素在文档流的最后渲染,并将 width 设为 100%,则会自动压到左右两个浮动元素的下面,随后在中间元素中再添加一个div元素并给其设置 margin 左右边距分别为左右两列的宽度,就可以将新元素调整到正确的位置。
html部分:
<div class="container">
<div class="left">this is left</div>
<div class="right">this is right</div>
<div class="center">
<div class="middle">
this is center
</div>
</div>
</div>
css部分:
.container {
width: 100%;
height: 100%;
overflow: hidden;
}
.left {
float: left;
width: 400px;
height: 800px;
background-color: black;
}
.center {
width: 100%;
height: 1000px;
background-color: yellow;
}
.middle {
background-color: #fff;
margin: 0 400px;
height: 850px;
}
.right {
float: right;
width: 400px;
height: 800px;
background-color: red;
}
- 试试利用 BFC
- 同样的左右两列元素优先渲染,并分别左右浮动。
- 接下来将中间元素设置 overflow: hidden; 成为 BFC 元素块,不与两侧浮动元素叠加,自然能够插入自己的位置。
html部分:
<div class="container">
<div class="left">this is left</div>
<div class="right">this is right</div>
<div class="center">
this is center
</div>
</div>
css部分:
.container {
width: 100%;
height: 100%;
overflow: hidden;
}
.left {
float: left;
width: 400px;
height: 800px;
background-color: black;
}
.center {
overflow: hidden;
height: 1000px;
background-color: yellow;
}
.right {
float: right;
width: 400px;
height: 800px;
background-color: red;
}
- 通过左右元素设置定位,中间元素设置 width: auto; 来实现
html部分:
<div class="container">
<div class="left">this is left</div>
<div class="center">
this is center
</div>
<div class="right">this is right</div>
</div>
css部分:
.container {
width: 100%;
height: 100%;
position: relative;
}
.left {
position: absolute;
left: 0;
top: 0;
width: 400px;
height: 800px;
background-color: black;
}
.center {
/* 如果没有这一句,那么,center这个div的文字就不会自动换行 */
width: auto;
margin: 0 400px;
height: 1000px;
background-color: yellow;
}
.right {
position: absolute;
top: 0;
right: 0;
width: 400px;
height: 900px;
background-color: red;
}
- 双飞翼布局
主要利用了浮动、负边距、相对定位三个布局属性,使三列布局就像小鸟一样,拥有中间的身体和两侧的翅膀。
html部分:
<div class="grid">
<div id="div-middle-02">
<div id="middle-wrap-02"><span>div-middle</span></div>
</div>
<div id="div-left-02"><span>div-left</span></div>
<div id="div-right-02"><span>div-right</span></div>
</div>
css部分:
#div-middle-02 {
float: left;
background-color: #fff9ca;
width: 100%;
height: 80px;
}
#div-left-02 {
float: left;
background-color: red;
width: 150px;
/* 重点看这里 */
margin-left: -100%;
height: 50px;
}
#div-right-02 {
float: left;
background-color: yellow;
width: 200px;
/* 重点看这里 */
margin-left: -200px;
height: 50px;
}
#middle-wrap-02 {
margin: 0 200px 0 150px;
background-color: pink;
}
11.流式布局和响应式布局怎么实现?原理是什么?
- 流式布局(百分比布局)在CSS2时代就有,主要指的是将页面中元素的宽度以百分比表示并进行排版,可以在不同分辨率下显示相同的版式
- 响应式布局的关键技术是CSS3中的媒体查询,可以在不同分辨率下对元素重新设置样式(不只是尺寸),在不同屏幕下可以显示不同版式
12.解释伪类和伪元素?
-
伪类一般反映无法在CSS中轻松或者可靠检测到的某个元素的状态或者属性;
-
伪元素表示DOM外部的某种文档结构。
目前所有伪元素有(加粗的是CSS3之后出现):
-
::after
-
::before
-
::first-letter
-
::first-line
-
::selection
-
::backdrop
-
::placeholder
-
::marker
-
::spelling-error
-
::grammar-error
13.解释一下 ":before" 和 "::after" 伪元素单冒号和双冒号的区别?
如果你的网站只需要兼容webkit、Firefox、Opera等浏览器,建议对伪元素采用双冒号的写法,如果不得不兼容IE浏览器,还是用CSS2的单冒号写法更安全。
原因:
- 在CSS2之前规范不明确的时候,伪元素和伪类都使用单冒号(:)来表示。
- 而CSS3规范中的要求使用双冒号(::)表示伪元素,以此来区分伪元素和伪类。
- 为了兼容过去的写法,CSS3之前的伪元素仍然可以使用单冒号(:)来表示,浏览器是可以解析的。
- 但是CSS3之后出现的伪元素必须用双冒号表示,不再支持单冒号的形式。
14.行内元素能不能设置上下内外边距?为什么?
15.物理像素、逻辑像素、设备独立像素?
16.解决适配问题?
rem+flexable.js
vm+vh
遇到的问题:多倍图问题、1px问题
二、JavaScript
1.JavaScript内置对象有哪些?
- Math
- Date
- Function
- Array
- Object
- Arguments
- Error
- RegExp
- String
- Number
- Boolean
其中,String、Number、Boolean又是基本包装类型。三种原始类型的值,在一定条件下会自动转化为对象,因此被称为原始类型的“包装类型”。它们是特殊的引用类型,既与其他的引用类型相似,同时又具有与各自的原始类型相应的特殊行为。
2.JavaScript内置对象Array、String有哪些方法(15个以上)?
- Array
push() //将一个或多个数据加入到数组的末端,并返回新的数组长度.
pop() //取出数组中的最后一项,修改length属性,并返回被删除的数据
shift() //取出数组中的第一个元素,修改length属性
unshift() //在数组最前面插入项,返回数组的长度
reverse() //翻转数组
sort() //即使是数组sort,也是根据字符,从小到大排序
// 带参数的sort是如何实现的?
concat() //把参数拼接到当前数组
slice() //从当前数组中截取一个新的数组,不影响原来的数组,参数start从0开始,end从1开始
splice(位置start,个数deleteCount,新元素options...) //删除或替换当前数组的某些项目,参数start, deleteCount, options(要替换的项目)
//以上方法的含义是删除从位置start起的deleteCount个元素,用新元素option替代(新元素option可以有很多个).
join() // 方法将数组的所有元素以给定字符串进行"串联"为一个字符串格式。
indexOf()、lastIndexOf() //根据字符找下标,如果没找到返回-1
every()、filter()、forEach()、map()、some()
- String
// 1 字符方法
charAt() //获取指定位置处字符
charCodeAt() //获取指定位置处字符的ASCII码
// 2 字符串操作方法
concat() //拼接字符串,等效于+,+更常用
slice(start,end) //从start位置开始,截取到end位置,end取不到
substring(start,end) //从start位置开始,截取到end位置end取不到
substr(start,length) //从start位置开始,截取length个字符
// 3 位置方法
indexOf() //返回指定内容在元字符串中的位置,该方法可以设置两个参数,.indexOf('要找的字符串',从某个位置p),
// 表示从某个位置p开始找特定字符串,如果找到,就返回找到的位置,否则返回-1;第二个参数如果省略,就从位置0开始找.
lastIndexOf() //从后往前找,只找第一个匹配的
// 4 去除空白
trim() //只能去除字符串前后的空白(包括空格,回车符,换行符,tab符)
// 5 大小写转换方法
to(Locale)UpperCase() //转换大写
to(Locale)LowerCase() //转换小写
// 6 其它
search() //基本等同于match,但是返回值为匹配的第一个位置。如果没有找到匹配,则返回-1
replace() //用于替换匹配的子字符串,一般情况下只替换第一个匹配,返回新字符串
split() //将字符串以指定的字符分割为数组
3.JavaScript数据类型有哪些?
根据 JavaScript 中的变量类型传递方式,分为基本数据类型和引用数据类型。其中基本数据类型包括Undefined、Null、Boolean、Number、String、Symbol (ES6新增,表示独一无二的值),而引用数据类型统称为Object对象,主要包括对象、数组和函数。
在参数传递方式上,有所不同:
-
函数的参数如果是简单类型,会将一个值类型的数值副本传到函数内部,函数内部不影响函数外部传递的参数变量
-
如果是一个参数是引用类型,会将引用类型的地址值复制给传入函数的参数,函数内部修改会影响传递参数的引用对象。
基本数据类型和引用数据类型的区别:
- 基本类型和引用类型存储于内存的位置不同,基本类型直接存储在栈中。
- 引用类型的对象存储在堆中,与此同时,在栈中存储了指针,而这个指针指向正是堆中实体的起始位置。
下面通过一个小题目,来看下两者的主要区别:
// 基本类型
var a = 10
var b = a
b = 20
console.log(a) // 10
console.log(b) // 20
上述代码中,a b都是值类型,两者分别修改赋值,相互之间没有任何影响。再看引用类型的例子:
// 引用类型
var a = {x: 10, y: 20}
var b = a
b.x = 100
b.y = 200
console.log(a) // {x: 100, y: 200}
console.log(b) // {x: 100, y: 200}
上述代码中,a b都是引用类型。在执行了b = a之后,修改b的属性值,a的也跟着变化。因为a和b都是引用类型,指向了同一个内存地址,即两者引用的是同一个值,因此b修改属性时,a的值随之改动
4.判断数据类型的方式?
- typeof
typeof返回一个表示数据类型的字符串,返回结果包括:number、boolean、string、symbol、object、undefined、function等7种数据类型,但不能判断null、array等
typeof Symbol(); // symbol 有效
typeof ''; // string 有效
typeof 1; // number 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof new Function(); // function 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效
-
instanceof
instanceof 是用来判断A是否为B的实例,表达式为:A instanceof B,如果A是B的实例,则返回true,否则返回false。instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性,但它不能检测null 和 undefined
[] instanceof Array; //true
{} instanceof Object;//true
new Date() instanceof Date;//true
new RegExp() instanceof RegExp//true
null instanceof Null//报错
undefined instanceof undefined//报错
-
constructor
constructor作用和instanceof非常相似。但constructor检测 Object与instanceof不一样,还可以处理基本数据类型的检测。不过函数的 constructor 是不稳定的,这个主要体现在把类的原型进行重写,在重写的过程中很有可能出现把之前的constructor给覆盖了,这样检测出来的结果就是不准确的。
-
Object.prototype.toString.call()
Object.prototype.toString.call() 是最准确最常用的方式。
Object.prototype.toString.call('') ; // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
5.null和undefined的区别?
6.事件冒泡和事件捕获?
7.阻止事件冒泡的几种方式?
8.js垃圾回收机制?
9.对闭包的理解,什么是闭包?闭包的优缺点?
谈及闭包这个概念首先要明白为什么需要使用闭包。我们在编写代码的过程中,一定会遇到多人开发的问题,既然是多人开发,变量的命名就很可能会重复,为了解决这个问题就提出了闭包的概念。通过闭包就可以实现在函数外通过一定条件操作局部变量的目的。
闭包由两部分组成:内层函数和内层函数所处的作用域(即有函数的嵌套才构成闭包),比如下面inner函数和其所处的作用域就构成了闭包。
function foo() {
var n = 456;
function inner() {
n += 1;
return n;
}
return inner;
}
var inner = foo();
var ret = inner();
ret = inner();
console.log(ret)
上面这段代码的结果是458,可以看到在外部inner函数被调用执行了两次,第二次变量值在第一次的基础上+1,就可以看出,变量n在函数执行后仍然存储在内存中,而没有回收。
- 优点(作用):隔离私有空间,防止全局污染;可以在函数外面有条件访问内部变量;延长变量的生命周期(能够延长也是因为变量没有被回收)
- 缺点:由于内层函数在外部被调用,所有外层函数内的局部变量不能回收(一直保存在内存中),这就会造成内存被占用严重的问题,在IE浏览器中严重的话会发生内存泄漏。
- 解决方案:对变量在外层函数内进行手动释放(置为null)
10.this使用场景及指向?
函数在定义的时候this是不确定的,只有在调用的时候才可以确定:
- 箭头函数中:指向父一级的this
- 定时器中:指向window
- 普通函数中:普通函数执行时,内部的this指向全局window
- 实例对象中:函数作为一个对象的方法,被该对象所调用,那么this指向的是该对象
11.修改this指向的方法?三者的区别是什么?
call、apply、bind
12.new关键字结合构造函数创建对象的步骤?
- new会在内存中创建一个新的空对象
- new 会让this指向这个新的对象
- 执行构造函数(给这个新对象添加属性和方法)
- new会返回这个新对象
13.解释原型链?
14.创建对象的方式?
15.实现继承的方式?优缺点?
16.理解js变量提升?
17.==和===的区别?==中强制类型转换后比较是怎么实现的?
18.编译型语言和解释型语言?
计算机不能直接理解任何除机器语言以外的语言,所以必须要把程序员所写的程序语言翻译成机器语言,计算机才能执行程序。将其他语言翻译成机器语言的工具,被称为编译器。
编译器翻译的方式有两种:一个是编译,另外一个是解释。两种方式之间的区别在于翻译时间点的不同。当编译器以解释方式运行的时候,也称之为解释器。
- 编译型语言:程序在执行之前需要一个专门的编译过程,把程序编译成为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依赖编译器,跨平台性差些。如 C、C++
- 解释型语言:解释型语言编写的程序不进行预先编译,以文本方式存储程序代码,会将代码一句一句直接运行。在发布程序时,看起来省了道编译工序,但是在运行程序的时候,必须先解释再运行,如JavaScript
编译型语言与解释型语言对比:
- 速度 —— 编译型语言比解释型语言执行速度快
- 跨平台性 —— 解释型语言比编译型语言跨平台性好
19.宏任务、微任务、任务队列和调度?
20.作用域?作用域链?
- 全局作用域:
- 局部作用域:?
- 块级作用域:?
21.数组和伪数组的区别?
22.原生js绑定事件的方式有几种?
- 在标签上通过 onClick="" 绑定
- 通过对象 .onclick 绑定
- 通过对象 .addEventListener 绑定
三、ES6
1.var、let、const的区别?
- 与Var相比、let和const定义的变量具有块级作用域,不会进行变量提升。
- let和const相比,let定义的变量值可以被修改,const定义的变量值不可以被修改。
但是,如果用const定义了一个对象,对象的属性值是可以被修改的,可以理解为const定义的是对象的地址(存储在栈内存中),而存储在堆内存中的属性值是可以被修改的。
2.聊聊promise?
3.创建promise对象的方法?
4.箭头函数的this指向?
箭头函数的this指向与该函数父一级的this指向相同。
5.合并对象的方法?
...解构
Object.assign()
7.扩展运算符(展开运算、剩余匹配)?
es6中的 ... 运算
8.ES6中允许对象的属性名动态传参
比如下面这段react代码中,用到了动态对象属性名动态传参
handleFormItem = (itemName, e) => {
this.setState({
[itemName]: e.target.value // 这是通过[]包裹动态传参
});
}
四、Web API
1.常见的API操作有哪些?
2.change事件和input事件的区别?
- input事件在输入框输入的时候回实时响应并触发
- change事件在input失去焦点才会考虑触发,它的缺点是无法实时响应。与blur事件有着相似的功能,但与blur事件不同的是,change事件在输入框的值未改变时并不会触发,当输入框的值和上一次的值不同,并且输入框失去焦点,就会触发change事件。
3.keyup事件、keydown事件和input事件的区别?
keydown
、keyup
属于键盘事件,input
属于文本事件。
keydown
:当用户按下键盘上的任意按键时触发,如果按住不放,会重复触发此事件。keyup
:当用户释放键盘上的按键时触发。input
:当元素内容发生改变时触发,这些元素指<input>
、<select>
、<textarea>
和指定了contenteditable
属性的元素。
举个例子:
当我们在一个输入框中输入文本时,会依次触发下列事件:keydown
事件 ——> input
事件 ——> keyup
事件。
五、jQuery
1.jquery的优点?
- 轻量级
JQuery非常轻巧,采用Dean Edwards编写的Packer压缩后,大小不到30KB,如果使用Min版并且在服务器端启用Gzip压缩后,大小只有18KB。
- 强大的选择器
JQuery允许开发者使用从CSS1到CSS3几乎所有的选择器,以及JQuery独创的高级而且复杂的选择器,另外还可以加入插件使其支持XPath选择器,甚至开发者可以编写属于自己的选择器。由于JQuery支持选择器这一特性,因此有一定CSS经验的开发人员可以很容易的切入到JQuery的学习中来。
- 出色的DOM操作的封装
JQuery封装了大量常用的DOM操作,使开发者在编写DOM操作相关程序的时候能够得心应手。JQuery轻松地完成各种原本非常复杂的操作,让JavaScript新手也能写出出色的程序。
- 可靠的事件处理机制
JQuery的事件处理机制吸收了JavaScript专家Dean Edwards编写的事件处理函数的精华,是的JQuery在处理事件绑定的时候相当可靠。在预留退路、循序渐进以及非入侵式编程思想方面,JQuery也做得非常不错。
- 完善的Ajax
JQuery将所有的Ajax操作封装到一个函数$.ajax()里,使得开发者处理Ajax的时候能够专心处理业务逻辑而无需关心复杂的浏览器兼容性和XMLHttpRequest对象的创建和使用的问题。
- 不污染顶级变量
JQuery只建立一个名为JQuery的对象,其所有的函数方法都在这个对象之下。其别名$也可以随时交流控制权,绝对不会污染其他的对象。该特性是JQuery可以与其他JavaScript库共存,在项目中放心地引用而不需要考虑到后期的冲突。
- 出色的浏览器兼容性
作为一个流行的JavaScript库,浏览器的兼容性是必须具备的条件之一。JQuery能够在IE6.0+,FF 2+,Safari2.+和Opera9.0+下正常运行。JQuery同时修复了一些浏览器之间的的差异,使开发者不必在开展项目前建立浏览器兼容库。
- 链式操作方式
JQuery中最有特色的莫过于它的链式操作方式——即对发生在同一个JQuery对象上的一组动作,可以直接接连写无需要重复获取对象。这一特点使得JQuery的代码无比优雅。
- 隐式迭代
当用JQuery找到带有“.myClass”类的全部元素,然后隐藏他们时。无需循环遍历每一个返回的元素。相反,JQuery里的方法都被设计成自动操作的对象集合,而不是单独的对象,这使得大量的循环结构变得不再必要,从而大幅度地减少代码量。
- 行为层与结构层的分离
开发者可以使用选择器选中元素,然后直接给元素添加事件。这种将行为层与结构层完全分离的思想,可以使JQuery开发人员和HTML或其他页面开发人员各司其职,摆脱过去开发冲突或个人单干的开发模式。同时,后期维护也非常方便,不需要在HTML代码中寻找某些函数和重复修改HTML代码。
- 丰富的插件支持
JQuery的易扩展性,吸引了来自全球开发者来编写JQuery的扩展插件。目前已经有超过几百种官方插件支持,而且还不断有新插件面试。
- 完善的文档
JQuery的文档非常丰富,现阶段多位英文文档,中文文档相对较少。很多热爱JQuery的团队都在努力完善JQuery中文文档,例如JQuery的中文API。
- 开源
JQuery是一个开源的产品,任何人都可以自由地使用并提出修改意见。
2.jquery两大特性?
链式编程、隐式迭代
3.jquery和zepto是什么关系,有什么联系?
4.jquery如何绑定事件?有几种类型和区别?
六、Ajax
1.通过原生js实现Ajax发送请求的步骤?
- 通过onload注册事件:
// 1. 创建一个 xhr 对象
var xhr = new XMLHttpRequest();
// 2. 设置请求的方式和路径
xhr.open('GET', '/time');
// 3. 发送请求
xhr.send(null);
// 4. 注册事件
xhr.onload = function () {
// 通过 xhr 的 responseText 获取到响应的响应体
console.log(this.responseText)
}
注意:如果是发送post方式的请求,需要在open和send中间设置请求头,send中添加要传递的参数(有格式要求:=连接属性和值;&连接不同的属性)。
var xhr = new XMLHttpRequest()
xhr.open('POST', '/query-post')
// 设置 Content-Type 为 application/x-www-form-urlencoded,这行代码不用死记硬背,去复制即可
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 需要提交到服务端的数据可以通过 send 方法的参数传递
// 格式:name=zhangsan&age=18
xhr.send('name=zhangsan&age=18')
xhr.onload = function () {
console.log(this.responseText)
}
- onload 是 HTML5 以后新增的方便获取响应的事件,过去获取浏览器返回内容的时候使用的是 onreadystatechange。
var xhr = new XMLHttpRequest()
// open 方法的第一个参数的作用就是设置请求的 method
xhr.open('POST', '/query-post')
// 设置 Content-Type 为 application/x-www-form-urlencoded,这行代码不用死记硬背,去复制即可
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 需要提交到服务端的数据可以通过 send 方法的参数传递
// 格式:name=zhangsan&age=18
xhr.send('name=zhangsan&age=18')
// 更改事件为onreadystatechange
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
// 后续逻辑......
}
}
2.ajax和axios、fetch的区别
七、Vue
1.描述Vue组件传值?
- 父向子传值
- 子向父传值
- 非父子关系传值
2.v-if 和v-show的区别?
3.路由懒加载?
4.事件总线的原理?
通过创建一个vue实例,将事件全部绑定到这个实例上,再进行使用。。。。。。。。。。
5.Vuex是什么?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
能够解决复杂项目的组件间传值的问题。
vuex流程图:
6.vuex中的配置项?
vuex中的配置项有5个:state、mutations、actions、getter(相当于vue中的计算属性)、module
。。。。。。。。。。。。
7.token和session的区别?
session和token都是用来保持会话,功能相同
session机制,原理
- session是服务端存储的一个对象,主要用来存储所有访问过该服务端的客户端的用户信息(也可以存储其他信息),从而实现保持用户会话状态。但是服务器重启时,内存会被销毁,存储的用户信息也就消失了。
不同的用户访问服务端的时候会在session对象中存储键值对,“键”用来存储开启这个用户信息的“钥匙”,在登录成功后,“钥匙”通过cookie返回给客户端,客户端存储为sessionId记录在cookie中。当客户端再次访问时,会默认携带cookie中的sessionId来实现会话机制。
- session是基于cookie的。
- cookie的数据4k左右
- cookie存储数据的格式:字符串key=value
- cookie存储有效期:可以自行通过expires进行具体的日期设置,如果没设置,默认是关闭浏览器时失效。
- cookie有效范围:当前域名下有效。所以session这种会话存储方式方式只适用于客户端代码和服务端代码运行在同一台服务器上(前后端项目协议、域名、端口号都一致,即在一个项目下)
- session持久化
用于解决重启服务器后session就消失的问题。在数据库中存储session,而不是存储在内存中。通过包:express-mysql-session
- 其它
当客户端存储的cookie失效后,服务端的session不会立即销毁,会有一个延时,服务端会定期清理无效session,不会造成无效数据占用存储空间的问题。
token机制,原理
- 适用于项目级的前后端分离(前后端代码运行在不同的服务器下)
请求登录时,token和sessionId原理相同,是对key和key对应的用户信息进行加密后的加密字符,登录成功后,会在响应主体中将{token:'字符串'}返回给客户端。客户端通过cookie、sessionStorage、localStorage都可以进行存储。再次请求时不会默认携带,需要在请求拦截器位置给请求头中添加认证字段Authorization携带token信息,服务器端就可以通过token信息查找用户登录状态。
8.watch侦听器和computed计算属性?
- computed:
当需要对data中的数据进行逻辑操作再进行使用时,使用计算属性。
- watch:
当要根据data中的数据变化得到一项新数据、开销较大、异步操作时使用侦听器。
。。。。。。。。。
9.修饰符?事件修饰符?指令修饰符?
修饰符是由点开头的指令后缀来表示的。
- 事件修饰符
事件修饰符指的是添加在事件后面的以.开头的后缀,可以限制事件的执行方式(比如.once表示时间只能触发一次)、通过键盘按键(比如.enter和.tab)或者鼠标按键(.left、.middle和.right)触发。
- 指令修饰符
同理指令修饰符是用来修饰指令的,也可以根据不同的修饰符设置不同的操作,实现这个操作需要通过binding.modifiers获取指令修饰符。
<template>
<div @click.once="fn()">
<p v-color.font="'red'">自定义指令&修饰符</p>
</div>
</template>
<script>
export default {
// 指令v-color:颜色可以设置
// 使用指令修饰符:bg 设置的背景 font 设置字体
directives: {
'color': {
bind (el, binding) {
// bg 设置的背景 font 设置字体
// 跟修饰符有关系
// 获取修饰符 binding.modifiers ===> {bg: true, font: true}
if (binding.modifiers.bg) {
el.style.backgroundColor = binding.value
}
if (binding.modifiers.font) {
el.style.color = binding.value
}
}
}
},
methods: {
fn () {
console.log('我只执行一次')
}
}
}
</script>
八、react
1.react生命周期?
如上图所示,react组件的声明周期可以按照三个阶段进行划分。
-
-
constructor 初始化数据
-
render 状态state中数据发生变化就会再次触发
-
componentDidMount 方法会在组件已经被渲染(挂载)到 DOM 中后运行
-
一般用于初始化一些资源
-
调用后台接口
-
启动定时任务
-
绑定全局事件(发布-订阅模式)
-
-
-
-
更新时
-
render 状态state中数据发生变化就会再次触发
-
componentDidUpdate 组件更新后被调用
-
props数据的变化也会导致该函数的触发
-
-
-
卸载时
-
componentWillUnmount 组件被卸载或者销毁之前被调用
-
一般用于销毁一些资源,释放内存(比如清理掉定时器任务)
-
-
2.关于react中state数据的修改?
state中的数据不可以直接修改,比如下面这种方式就是错误的:代码虽然操作了修改了内存中的数据,但是页面中显示的数据却没有发生响应式变化(原因:react中是通过setState方法监测数据变化的,下面的方法中绕过了setState方法,虽然修改了内存中的数据,但实际上却没有监测到,也就没有办法进行对页面进行响应式更新)
this.state.msg = 'hello'
只能按照如下方式(通过setState)进行修改:
this.setState({
msg: 'hello'
})
关于setState方法的注意事项:
针对于下面的数据:
constructor(props) {
super(props);
this.state = {
n: 1
}
}
- setState的数据更新是异步的,要想得到最新的数据,需要使用回调函数
this.setState({
n: 101
});
console.log(this.state.n); // 这是输出的数据结果还是原始的 1
对代码做如下更改:
this.setState({
n: 101
}, () => {
// 该函数触发的时候,数据已经完成更新
console.log(this.state.n);
});
- 频繁调用setState不会导致页面频繁更新,为了提高页面的渲染性能
this.setState({
n: this.state.n + 1
})
this.setState({
n: this.state.n + 1
})
this.setState({
n: this.state.n + 1
})
执行完上面的代码后,页面中显示的 this.state.n 的结果为 2,原因是进行的三次setState调用,在react内部会将其合并,只有最后一次的数据操作能够生效。
3.事件函数中的this?
事件处理函数要想使用组件实例对象有两种办法:
- 使用箭头函数
- 普通函数(this默认为undefined),必须显示绑定this
- this.handle = this.handle.bind(this); --------------------->这段代码写在constructor内
class TestEvent extends React.Component {
constructor(props) {
super(props);
this.state = {
info: 'nihao'
}
// 如果使用普通函数,必须在这里进行this绑定
this.handle = this.handle.bind(this);
}
// handle = () => {
// // 事件函数中的this是组件的实例对象
// console.log(this)
// }
handle () {
// 如果使用普通函数,那么默认的this是undefined
console.log(this)
}
render() {
return (
<div>
<div>{this.state.info}</div>
<div>
<button onClick={this.handle}>点击</button>
</div>
</div>
);
}
}
ReactDOM.render(<TestEvent/>, document.getElementById('root'));
4.事件的传参方式?
- 使用自定义属性携带数据
<li data-id={item.id} onClick={this.handle} key={item.id}>{item.bname}</li>
handle = (e) => {
console.log(e.target.dataset.id)
}
- 使用bind方式传递参数
<li onClick={this.handle.bind(this, item.id, 123)} key={item.id}>{item.bname}</li>
handle = (id, n, e) => {
// 如果使用bind方式传递参数,那么事件对象始终在最后一个参数传递
console.log(id, n)
console.log(e)
}
- 使用箭头函数传递参数(建议e事件对象放到最后一个参数)
<li onClick={(e) => {this.handle(item.id, 456, e)}} key={item.id}>{item.bname}</li>
handle = (id, n, e) => {
// 如果使用bind方式传递参数,那么事件对象始终在最后一个参数传递
console.log(id, n)
console.log(e)
}
九、微信小程序
1.小程序生命周期?
- 全局生命周期
- onLaunch:小程序初次加载时触发(只能触发一次)
- onShow:小程序进入前台运行显示时触发
- onHide:小程序进入后台隐藏运行时触发
- onError:小程序出错时触发
- 页面生命周期
。。。。。。
2.数据的修改是同步的,页面的更新是异步的
十、浏览器相关
1.cookie、sessionStorage和localStorage的区别?
cookie、sessionStorage、localStorage 都是用于本地存储的技术:其中 cookie 出现最早,但是存储容量较小,仅有4KB;sessionStorage、localStorage存储容量要比cookie大很多,为5MB。
接下来对 sessionStorage、localstorage 进行比较,其中sessionStorage 的数据存储局限于浏览器窗口,只适合于单页面应用程序使用,因为sessionStorage打开浏览器新标签,会话状态不会共享;而localstorage 的数据存储位于本地文件夹中,用户关闭浏览器后再次打开时,数据仍会存在。
2.页面渲染过程?
3.什么是同源策略?
- 源(origin)
就是协议、域名和端口号。若地址里面的协议、域名和端口号均相同则属于同源。
以下是相对于 http://www.a.com/test/index.html 的同源检测:
- http://www.a.com/dir/page.html ----成功
- http://www.child.a.com/test/index.html ----失败,域名不同
- https://www.a.com/test/index.html ----失败,协议不同
- http://www.a.com:8080/test/index.html ----失败,端口号不同
- 同源策略
同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以a.com下的js脚本采用ajax读取b.com里面的文件数据是会报错的。
- 不受同源策略限制的
- 页面中的链接,重定向以及表单提交是不会受到同源策略限制的。
- 跨域资源的引入是可以的。但是js不能读写加载的内容。如嵌入到页面中的<script src="..."></script>,<img>,<link>,<iframe>等。
4.什么是跨域?为什么进行跨域?
- 跨域
只要协议、域名、端口号有一个不同就是跨域。
- 跨域的原因
跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号(如存在)相同,则允许相互访问。为了防止某域名下的接口被其他域名下的网页非法调用,是浏览器对JavaScript施加的安全限制。也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。跨域问题是针对JS和ajax的,html本身没有跨域问题,比如a标签、script标签、甚至form标签(可以直接跨域发送数据并接收数据)等。
5.如何解决跨域问题?
- jsonp
利用script标签可跨域的特点,在跨域脚本中可以直接回调当前脚本的函数。
- cors
服务器设置HTTP响应头中Access-Control-Allow-Origin值,解除跨域限制。
注意:这两个跨域方案都存在一个致命的缺陷,严重依赖后端的协助。
下面就介绍一种前端独立就能解决的跨域方案:
- 反向代理(Reverse Proxy)
指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
6.Jsonp的原理是什么?
其本质是利用了script标签具有可跨域的特性,由服务端返回预先定义好的javascript函数调用,并且将服务端数据以该函数参数的形式传递过来。
客户端代码:为什么要定义callback?首先我们知道,这个get请求发出去后如何接口请求回来的数据,callback=func则可以帮我们做这件事。(需要在客户端声明一个与callback=“func”的func同名的函数,通过jsonp方式成功接收到服务器数据的时候就会自动触发这个回调函数)
<button id="btn">点击</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$('#btn').click(function(){
var frame = document.createElement('script');
frame.src = 'http://localhost:3000/article-list?name=leo&age=30&callback=func';
$('body').append(frame);
});
function func(res){
alert(res.message+res.name+'你已经'+res.age+'岁了');
}
</script>
服务端代码:
router.get('/article-list', (req, res) => {
console.log(req.query, '123');
let data = {
message: 'success!',
name: req.query.name,
age: req.query.age
}
data = JSON.stringify(data)
res.end('func(' + data + ')');
});
举两个小例子:
1.通过原生js方式使用jsonp
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
*{
margin: 0;
padding: 0;
list-style: none;
}
ul{
background-color: #ccc;
width: 172px;
}
</style>
</head>
<body>
<input type="" name="" id='inp'>
<ul>
</ul>
<script type="text/javascript">
//1获取input
//2.注册事件,获取value
//3动态创建script
//4追加到body、
var inp = document.getElementById('inp')
var ul = document.querySelector('ul')
function suggest_so(data){
console.log(data)
var {result} = data
ul.innerHTML = ''
for(var i =0;i<result.length;i++){
// 创建li
var li = document.createElement('li')
li.innerHTML = result[i].word;
ul.appendChild(li)
}
}
inp.oninput = function(){
// 判断创建script是否一致
if(document.getElementsByClassName('ss').length>0){
document.getElementsByClassName('ss')[0].remove()
}
var val = inp.value;
var jsonp = document.createElement('script')
jsonp.src = 'https://sug.so.360.cn/suggest?callback=suggest_so&encodein=utf-8&encodeout=utf-8&format=json&fields=word&word='+val
jsonp.className = 'ss'
document.body.appendChild(jsonp)
}
</script>
</body>
</html>
2.通过jQuery封装的ajax方式使用jsonp
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
list-style: none;
}
ul {
background-color: #ccc;
width: 172px;
}
</style>
<script type="text/javascript" src="jquery-1.12.1.js"></script>
<script type="text/javascript" src="template-web.js"></script>
</head>
<body>
<input type="" name="" id="inp" />
<ul></ul>
<script type="text/html" id="tpl">
{{each result value}}
<li>{{value.word}}</li>
{{/each}}
</script>
<script type="text/javascript">
$(function(){
$('#inp').on('input',function(){
$.ajax({
url:'https://sug.so.360.cn/suggest?callback=suggest_so&encodein=utf-8&encodeout=utf-8&format=json&fields=word&word='+$(this).val(),
dataType:'jsonp',
jsonpCallback:'suggest_so',
success:function(data){
var {result} = data;
var str = template('tpl',{result})
$('ul').html(str)
}
})
})
})
</script>
</body>
</html>
7.反向代理的实现原理?
实现原理:
反向代理需要用到nginx。反向代理是在服务器端进行处理。首先修改hosts文件,将域名指向开发者的电脑本身,把自己伪装成服务端,再通过nginx对不同的请求进行转发,把静态资源指向开发者本地电脑的资源,将接口指向实际的服务器。
可以理解为把饭店设置在了黑社会的楼下,去楼下买酱排骨饭的时候,饭店米饭自己做,酱排骨则偷偷跑去别的饭店买。
程序运行过程:
-
浏览器访问页面,假设访问淘宝页面:taobao.com/index.html
-
taobao.com域名解析先经过hosts文件配置,发现taobao.com域名指向127.0.0.1,则向本机发起请求。
-
nginx接收到taobao.com/index.html请求,根据nginx的配置,将把这个请求转发给127.0.0.1:3000。
-
浏览器运行index.html文件,发起taobao.com/api/getNew请求
-
nginx接收到taobao.com/api/getNew请求请求,根据nginx的配置,将把这个请求转发给真正的淘宝服务器中。
-
淘宝服务器将数据返回给nginx,再返回给浏览器执行。
8.浏览器中的异步操作场景有哪些?回调队列是什么?
- 定时任务
- ajax的回调函数
- 事件处理函数
十一、网络相关
网络安全
1.Web常见攻击手段?
- XSS 攻击
- CSRF 攻击
- SQL 注入
- DDOS 攻击
- SYN 攻击
网络协议
1.网络协议有哪几种?
2.三次握手,四次挥手?
性能优化
1.什么是SEO?
2.什么是CDN?
资源加速服务平台
3.提高页面加载速度的方法?
这个问题从两个方面来回答:1.减少资源体积;2.减少请求次数
- 减少资源体积:
- 代码压缩
- 按需加载(代码分割)
- gzip二进制压缩(服务端操作,压缩比非常高,比如100kb的文件可以压缩至30kb)
- 减少请求次数
- 合并图片为精灵图
- 服务端渲染SSR(server side render):把渲染页面的工作交给服务器来做
- 页面静态化(服务端操作):提前生成好页面,服务器直接发送生成好的页面响应给浏览器(比如京东的商品页,这种页面定期的在服务器更新、渲染,浏览器得到的都是现成的页面)
- 同构(SEO)??
路由懒加载。。。。。。第三方依赖采用CDN的方式。。。。。。
4.计算属性及其缓存问题?