1 html的标签元素可以分为哪几种?具体说明哪几个种类 举例说明
html的标签元素可以分为3类:
块状元素(块元素)
举例: <div> <h1> - <h6> <ul> <ol> <li> <p>
行内元素(内联元素)
举例: <span> <em> <i> <strong>
行内块状元素(可变元素)
<img> <input>
2 假如现在需要把一个div水平垂直居中,你有多少种方法?
确定宽高
1 绝对定位和负margin(宽高的一半)
2 绝对定位 + left/right/bottom/top + margin(知道父和子容器的宽高的时候可以这么用)
不定宽高
1 绝对定位和tranfrom(宽高的一半)
2 flex 布局 justify-content:center 和 align-items: center;
3 grid布局 搭配margin使用(父元素设置displaay:grid,子元素设置margin:auto)
4 table-cell + vertical-align + inline-block/margin: auto (父元素设置display: table-cell; text-align: center; vertical-align: middle; 子元素设置 display:inline-black; || margin: auto)
3 tranfrom 那个translate为什么是-50%
因为定位默认是左上角定位 假设屏幕中间有一个十字,那么定位之后 他就在第四象限,而我们需要这个div的中间在中间,所以我们需要再往左,往上偏移自身的一半
4 简单介绍一下flex布局
布局的传统解决方案,基于盒子模型,依赖display属性+position属性+float属性,他对于特殊布局不方便,为此,2009年 w3c引入了一种新的布局方式——flex布局,他可以简单,完整,响应式的实现各种页面布局。目前是所有的浏览器都支持。采用flex布局之后,其所有的子元素都成为容器成员,成为felx项目。然后,它的属性有:
- flex-direction 决定主轴的方向 flex默认分为主轴和侧轴,设置flex布局之后默认按 row排列
- flex-wrap 默认是在一条线上排列 如果一条线上排列不下的时候,他决定是否换 行,默 认有warp
- flex-flow flex-direction和 flex-wrap的简写,默认是row nowarp
- justify-content
justify-content
属性定义了项目在主轴上的对齐方式。 - align-items
align-items
属性定义项目在交叉轴上如何对齐。 - align-content
align-content
属性定义了多根轴线的对齐方式。如果项目只有一根轴 线,该属性不起作用。
5 刚才有聊到定位 简单介绍一下定位 它的属性 简单说一下
定位他有五个值
position:static;
代表默认值,没有定位,也可以用来取消之前设置的定位值。
position:absolute;
绝对定位,它的参照物是包含块,也就是离自己最近的有定位属性的祖先级元素。如果祖先元素都没有定位属性,则默认按照浏览器的窗口(body)来定位。我们可以通过给祖先元素设置position:relative/absolute/fixed来让祖先元素变成包含块,通常情况下,我们会用position:relative来设置祖先元素为包含块,因为它不会脱离文档流,不会对布局造成影响。通过left、top、right、bottom来给绝对定位的元素设置偏移值。绝对定位是脱离文档流的,它原来所占位置不会保留
position:fixed;
固定定位,fixed参照物是浏览器的整个窗口。也会使元素脱离文档流。也是通过设置left、top、right、bottom来确定位置。
position:relative;
相对定位,它的参照物是自己本身,可以通过left、top、right、bottom 设置偏移值。它并没有脱离文档流,所以原来所占的位置依然会保留。相对定位并不会影响其他元素的布局。
position:sticky
黏性定位。设置该属性后,只有当滑动到这个位置时,才会生效。生效后效果相当于固定定位fixed。也是通过设置left、top、right、bottom来确定位置。
6 假如给一个盒子设置相对定位给他设置top left 各20 那他是根据谁进行偏移的呢
相对于自身进行偏移 相对定位不设置偏移量的时候 对元素没有任何影响,设置了偏移量,则基于自身初始的位置进行偏移
7 有了解过防抖跟节流吗? 简单介绍一下
防抖:就是在用户操作某事件之后等待多少秒才执行的函数,如果再次期间用户点击了,那么就清空重新计时,
function getfn(fn,wait){
let timeout=null; // 设置一个时间戳
return ()=>{
//逻辑: 首先timeout为null 所以他走的是false
// 但是因为settimeout设置了延迟2秒,所以他不会立即输出
// 而同时也将settimeout()执行结果赋值给了timeout 所以此时timeout为真
// 然后因为在两秒之内用户一直输入,再次执行这个方法,
// 进行判断的时候,timeout为真 所以把上一个定时器给清除了
// 当两秒之后事件执行完毕,此方法被回收了,再次调用此方法相当于重新调用
if(timeout){
clearTimeout(timeout);
}
timeout=setTimeout(fn,wait)
}
}
节流: 节流就是原本频繁发生的事件,在运用节流后减少了事件发生的次数,一定程度上优化了性能,,也是设置一个时间戳为空,刚开始对时间戳取反,
function fengzhuang(fn,wait){
let timeout=null;
return function(){
if(!timeout){
timeout=setTimeout(()=>{
fn(),
timeout=null;
},wait);
}
}
}
8 你说一下js的数据类型有哪些?
基本数据类型:
字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)
引用数据类型(对象类型):
对象(Object)、数组(Array)、函数(Function)。
9 基本数据类型和对象类型存储的区别?
基本数据类型的值直接在栈内存中存储,值与值之间独立存在,修改一个变量不会影响到其他变量。
对象是保存在堆内存中的,每创建一个新对象,就会在堆内存中开辟出一个新空间,而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用,当其中一个通过变量修改属性时,另一个也会受到影响。
10 var let 跟const的区别
var 声明的范围是函数作用域,let 和 const 声明的范围是块作用域
var 声明的变量会被提升到函数作用域的顶部,let 和 const 声明的变量不存在提升,且具有暂时性死区特征
var 允许在同一个作用域中重复声明同一个变量,let 和 const 不允许
在全局作用域中使用 var 声明的变量会成为 window 对象的属性,let 和 const 声明的变量则不会
const 的行为与 let 基本相同,唯一 一个重要的区别是,使用 const 声明的变量必须进行初始化,且不能被修改
关键字 | 变量提升 | 块级作用域 | 重复声明同名变量 | 重新赋值 |
var | √ | × | √ | √ |
let | × | √ | × | √ |
const | × | √ | × | × |
11 用const 定义了一个数组 里边是一个1那么它可以改吗
可以 我们知道const的特点是 声明一个不可修改的常量,且必须在声明的同时初始化值。但是const还有一个特点就是可以更改对象的属性
Array和Object都是引用类型,当用const声明数组和对象时,const声明的常量保存的仅仅是目标的指针,这就意味着只要保证数组和对象的指针不发生改变,修改其中的值是被允许的。
const arr = [1,2,3,4,5]
arr[0] = 2 // 合法
arr.push(6) // 合法
console.log(arr) //[2,2,3,4,5,6]
arr = [1,2,3] // 错误
12 简单说一下深浅拷贝
浅拷贝:
浅拷贝就是通过赋值的方式进行拷贝,那为什么说这是浅拷贝呢?就是因为赋值的方式只会把对象的表层赋值给一个新的对象,如果里面有属性值为数组或者对象的属性,那么就只会拷贝到该属性在栈空间的指针地址,新对象的这些属性数据就会跟旧对象公用一份,也就是说两个地址指向同一份数据,一个改变就会都改变。
深拷贝:
是会一个一个的进行拷贝,不会说,新对象的属性数据会跟旧对象公用一份,他是完全独立的
function deepClone(source){
const targetObj= source.constructor == Array? [] :{}; //定义了一个空容器
for(let keys in source){ //将source对象中的属性一一赋值给keys
if(source.hasOwnProperty(keys)){ //判断source对象是否有这个属性
if(source[keys] && typeof source[keys]=='object'){ //如果有这个属性并且是引用数据类型
targetObj[keys]= source.constructor == Array? [] :{};//判断这个子属性是数组还是对象(这是引用层代码)
// 引用数据类型
targetObj[keys]=deepClone(source[keys]); //进行递归,直至都是基本数据类型
}else{
// 基本数据类型
targetObj[keys]=source[keys]; //基本数据类型直接赋值
}
}
}
return targetObj;
}
13 深拷贝的方法 除了刚刚那个递归拷贝
1 json.对象的方法实现(常用) json.parse(JSON.stringify(arr))
2 jqery里面的extend方法;
var b = $.extend(true, {}, a); // 第一个参数true为深拷贝,第二个参数为目标对象,第三个参数为源对象即你用拷贝那个数据
14 如何判断一个数组为空? 你有多少种方法
1 通过数组中的.length属性进行判断 array.length == 0 判断是否为空
2 通过直接比较判断是否为空 array == false ?console.log(’为空‘) :console.log('不为空')
3 JSON.stringify(data) ==="[]" ? console.log(’为空‘) :console.log('不为空')
15 如何判断一个对象为空?
1 通过json自带的stringfy()方法进行判断
JSON.stringify(obj) ==="{}"? console.log(’为空‘) :console.log('不为空')
2 通过for in 进行判断 若不为空 其中有item项 返回false 不为空 若是空数组 返回true 为空
function isEmptyObj(obj) {
for(let item in obj) {
return false
}
return true
}
console.log('对象是否为空:', isEmptyObj({a:"123"}))
3 通过es6 的object.keys进行判断
Object.keys()返回的是一个数组 所以有length的属性可以进行 ===0 的判断
Object.keys(obj).length === 0
4 Object.getOwnPropertyNames()方法
Object.getOwnPropertyNames()方法会返回一个数组,如果传入的是数组,那么返回的就是原数组索引组成的一个新的数组,如果传入的是一个对象,那么,返回的是对象中的属性组成的新数组。
Object.getOwnPropertyNames(obj).length === 0
16 如何判断一个对象是否为数组,函数。
//方法一:instanceof
var arr = [1,2,3,1];
console.log(arr instanceof Array); // true
var fun = function(){};
console.log(fun instanceof Function); // true
//方法二:constructor:
var arr = [1,2,3,1];
console.log(arr.constructor === Array); // true
var fun = function(){};
console.log(arr.constructor === Function); // true
//方法三 Object.prototype.toString()
Object.prototype.toString()
let arr =[]
let obj = Object.prototype.toString.call(arr);
//方法四 判断数组 Array.isArray()
console.log(Array.isArray(arr)); //返回true
17 你使用过git吗 能简单的说一下命令吗
git clone 从远程仓库克隆代码到本地
git init 初始化本地仓库
git add 文件名|* 将文件提交到暂存区
git commit -m '注释' 将文件提交到本地仓库
git status 查看状态,是否还有文件没有提交
git push 将本地仓库中的代码上传到之前克隆的远程仓库中
git log 查看历史提交记录
git reset --hard 版本号 版本回退
18 你es6了解多少,简单说一下?
es6 新增语法
let
let所声明的变量只有所处的块级作用域有效
关键字就是用来声明变量的
防止循环变量 编程全局变量
使用let关键字声明的变量没有变量提升
使用let关键字声明的变量具有暂时性四死区特征
const
const声明的变量是一个常量
既然常量不能重新进行赋值,如果是基本数据类型,不能更改值,如果是复杂数据类型,不能更改地址值
声明const的时候必须给定值
let const var 的区别
使用var 声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象
使用let声明的变量,其作用域为该语句所在的代码块中,且不存在变量提升
使用const 声明的是常量,在侯敏出现的代码中不可以再修改该常量的值
解构赋值
解构赋值就是把数据结构分解,然后给变量进行赋值
如果结构不成功,变量跟数值个数不匹配的时候,变量的值为undefined
数组解构用中括号包裹,多个变量用逗号隔开,对象解构用花括号包裹,多个变量用逗号隔开
利用解构赋值能够让我们方便的去取对象中的属性跟方法
箭头函数
箭头函数中不绑定this,箭头函数中的this指向是它所定义的位置,
可以简单理解成,定义箭头函数中的作用域的this指向谁,它就指向谁
箭头函数的优点在于解决了this执行环境所造成的一些问题。比如:
解决了匿名函数this指向的问题(匿名函数的执行环境具有全局性),
包括setTimeout和setInterval中使用this所造成的问题
剩余参数
function(...event){}
剩余参数语法允许我们将一个不定数量的参数表示为一个数组,不定参数定义方式,这种方式很方便的去声明不知道参数情况下的一个函数
构造函数方法:Array.from()
Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)
实例方法
find() 找出第一个符合条件的数组成员 没有找到返回undifined
findIndex() 找出第一个符合条件的数组成员的位置 如果没有找到返回-1
includes() 判断某个数组是否包含数组的值 返回布尔值
startswith() 表示参数字符串是否在原字符串的头部,返回布尔值
endswith() 表示参数字符串是否在原字符串的尾部,返回布尔值
repeat() repeat方法表示将原字符串重复n次,返回一个新字符串
字符串创建
ES6新增的创建字符串的方式,使用反引号定义(模板字符串)
在模板字符串中 可以解析变量 ${变量名}
在模板字符串中 可以调用方法 ${方法名()}
Set 数据结构
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值
Set本身是一个构造函数,用来生成 Set 数据结构
19 比如说现在数组需要去重 你用es6的方法可以用几种?
//(1)拓展运算符 + new Set 方法
let narr1 = [...new Set(arr)]
//(2)Array.from + new Set 方法
let narr2 = Array.from(new Set(arr))
//(3)new Map() + filter方法
let myMap = new Map()
let narr3 = arr.filter((item) => {
return !myMap.has(item) && myMap.set(item, 1)
})
其他的去重方法
1、利用for嵌套for,然后splice去重(ES5中最常用)
function unique(arr){
for(var i=0; i<arr.length; i++){
for(var j=i+1; j<arr.length; j++){
if(arr[i]==arr[j]){ //第一个等同于第二个,splice方法删除第二个
arr.splice(j,1);
j--;
}
}
}
return arr;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}] //NaN和{}没有去重,两个null直接消失了
2、利用indexOf去重
function unique(arr){
if(!Array.isArray(arr)){
alert("error")
return
}
let array = []
for(let i=0; i<arr.length; i++){
if(array.indexOf(arr[i]) === -1 )){
array.push[arr[i]]
}
}
}
3、利用includes
function unique(arr){
if(!Array.isArray(arr)){
alert("error")
return
}
let array = []
for(let i=0; i<arr.length; i++){
if(!array.includes(arr[i]) )){ //includes 检测数组是否有某个值
array.push[arr[i]]
}
}
}
20.Cookie、storage 的区别?什么时候使用?
1. cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。localStorage不会自动把数据发给服务器,仅在本地保存。
2. cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。
3. 存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
4. 数据有效期不同,
localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;
cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
5. WebStorage 支持事件通知机制,可以将数据更新的通知发送给监听者。
6. WebStorage 的 api 接口使用更方便。
使用场景:
localStorage可以用来统计页面访问次数。
cookie一般存储用户名密码相关信息,一般使用escape转义编码后存储。
补充
21 BFC
BFC
(Block Formatting Context),即块级格式化上下文,它是页面中一个独立的容器,容器中的元素不会影响到外面的元素
触发条件
触发BFC
的条件包含不限于:
- 根元素,即HTML元素
- 浮动元素:float值为left、right
- overflow值不为 visible,为 auto、scroll、hidden
- display的值为inline-block、inltable-cell、table-caption、table、inline-table、flex、inline-flex、grid、inline-grid
- position的值为absolute或fixed
22 清除浮动的方法
方法一:使用带 clear 属性的空元素
在浮动元素后使用一个空元素,并在 CSS 中赋 予.clear{clear:both;}属性即可清理浮动。
方法二:使用 CSS 的 overflow 属性
给浮动元素的容器添加 overflow:hidden;或 overflow:auto;可以清除浮动,另外在 IE6 中还 需要触发 hasLayout ,例如为父元素设置容器宽高或设置 zoom:1。 在添加 overflow 属性后,浮动元素又回到了容器层,把容器高度撑起,达到了清理浮动 的效果。
方法三:给浮动的元素的容器添加浮动
给浮动元素的容器也添加上浮动属性即可清除内部浮动,但是这样会使其整体浮动,影 响布局,不推荐使用。
方法四:使用 CSS 的:after 伪元素
结合:after 伪元素(注意这不是伪类,而是伪元素,代表一个元素之后最近的元素)和 IEhack ,可以完美兼容当前主流的各大浏览器,这里的 IEhack 指的是触发 hasLayout。 给浮动元素的容器添加一个 clearfix 的 class,然后给这个 class 添加一个:after 伪元素实 现元素末尾添加一个看不见的块元素清除浮动
23 数组常用方法
增
前三种是对原数组产生影响的增添方法,第四种则不会对原数组产生影响
push() 接受任意数量的参数,并把他们添加到数组的末尾,返回数组的最新长度
unshift() 开头添加
splice()
array.splice(index,howmany,item1,.....,itemX)
index | 必需。规定从何处添加/删除元素。 该参数是开始插入和(或)删除的数组元素的下标,必须是数字。 |
howmany | 可选。规定应该删除多少元素。必须是数字,但可以是 "0"。 如果未规定此参数,则删除从 index 开始到原数组结尾的所有元素。 |
item1, ..., itemX | 可选。要添加到数组的新元素 |
concat() 首先会创建一个当前数组的副本,然后再把它的参数添加到副本末尾,最后返回这个新构建的数组,不会影响原始数组
删
下面三种都会影响原数组,最后一项不影响原数组
pop() 删除数组的最后一项,同时减少数组的length
值,返回被删除的项
shift() 删除数组的第一项,同时减少数组的length
值,返回被删除的项
splice() 传入两个参数,分别是开始位置,删除元素的数量,返回包含删除元素的数组
slice() 创建一个包含原有数组中一个或多个元素的新数组,不会影响原始数组
arrayObject.slice(start,end)
start 必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2指倒数第二个元素,以此类推。
end 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。
改
即修改原来数组的内容,常用splice
传入三个参数,分别是开始位置,要删除元素的数量,要插入的任意多个元素,返回删除元素的数组,对原数组产生影响
查
即查找元素,返回元素坐标或者元素值
indexOf() 返回要查找的元素在数组中的位置,如果没找到则返回 -1
find() 返回第一个匹配的元素
includes() 返回要查找的元素在数组中的位置,找到返回true
,否则false