HTML、CSS相关
HTML5新增的标签
- 语义标签:header、hgroup、article、aside、footer、nav、section、dialog、summary
- 增强型表单:date、datetime、month、week
- 音视频:video、source、audio
- canvas、svg
前端HTML5几种存储方式
cookies,4KB,与服务端通信,设置失效时间- 本地存储
localStorage5M,永久有效 - 本地存储
sessionStorage5M,当前浏览器窗口或标签关闭之前有效 - 离线缓存
Application Cache配置manifest文件 - Web SQL 关系数据库,通过SQL语句访问
- indexedDB 索引数据库
src 和 href 的区别?
src:source源,指向外部资源的位置,src指向的内容会嵌入到文档中当前标签所在的位置
- img标签
- script标签
- iframe标签
href:超文本引用,用来建立当前元素和文档之间的链接
- link标签
- a标签 区别
- 浏览器识别href引用的文档并对该文档进行下载,同时不会停止当前文档的处理,「这也是建议用link方式引入css而不用import的原因」
- 当浏览器解析到src引用时,会暂停浏览器的渲染,直到该资源加载完毕,「这也是建议将javascript脚本放在底部的原因」
rem原理
rem是相对长度单位,相对于根元素(即html元素)font-size计算值的倍数
拿到设计稿宽度640px,把宽度设置成16份,那么1rem=640px/16=40px
标准盒模型和怪异盒模型
- 标准盒模型:width和height指的是content的宽度和高度,
一个块的总宽度= width + margin(左右) + padding(左右) + border(左右) - 怪异盒模型:width和height指的是content+padding+border,
一个块的总宽度= width + margin(左右) 即width已经包含了padding和border值
position的值
- static 默认值
- relative 相对于其本身的位置移动
- absolute 绝对定位,相对于其已定位的父元素
- fixed 绝对定位,相对于窗口定位,不会滚动
- sticky relative和fixed的结合
css的全称及含义
层叠样式表Cascading Style Sheets
层叠是什么意思?
层叠:就是对一个元素多次设置同一个样式,这将使用最后一次设置的属性值
css选择器
包括哪些?
元素选择器、类选择骑、id选择器、通配选择器(* )、后代选择器、子元素选择器、伪类选择器、属性选择器、兄弟选择器、
优先级如何?
权重
!important > 内联样式 > id选择器 > 类、伪类、属性选择器 > 标签、伪元素选择器
!important最高- 内联样式,如: style="...",权值为1000。
- ID选择器,如:#content,权值为0100。
- 类,伪类、属性选择器,如.content,权值为0010。
- 类型选择器、伪元素选择器,如div p,权值为0001。
- 通配符、子选择器、相邻选择器等。如* > +,权值为0000。
CSS中link和@import的区别?
- link是html的标签,不仅仅可以引入css文件;@import是css引入的一种方式
页面加载时,link引用的css会同时加载;@import会等到页面加载完再加载兼容性的差别,@import是css2提出的,IE5以上才支持
CSS3新增的伪类有哪些?
nth-child(n)、last-child、first-child、nth-of-type(n)、empty等
浮动元素引起的问题和解决方案?
浮动的问题:
1.父元素的高度无法被撑开,影响与父元素同级的元素
2.与浮动元素同级的非浮动元素(内联元素)会跟随其后
3.若非第一个元素浮动,则该元素之前的元素也需要浮动,否则会影响页面显示的结构
解决方案
1.给父元素添加清除浮动样式(伪元素的方式)
2.在最后一个浮动元素后面添加属性为clear:both;的元素
3.overflow:hidden/auto
什么是BFC?
块级格式化上下文,独立的渲染区域,容器内的不会影响到外面的容器。
如何触发BFC
- 浮动元素
- 绝对定位
- display:inline-block/table-cells/flex
- overflow:除了visible以外的值(hidden/auto/scroll) 应用场景
- 利用BFC避免margin重叠。
小知识:margin为什么会重叠?
在普通文档流中,两个或多个块级盒子的垂直相邻边界会重合。
margin的定义不是让元素移动xxpx,而是这个元素的旁边必须有xxxpx的的空白
- 清除浮动
CSS设置多行溢出
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
less和css的区别
less是CSS预处理语言,它扩展了CSS 语言,增加了变量、Mixin、函数等特性,使CSS更易维护和扩展。
可以使用嵌套式声明
display:inline-block默认有空格
元素被当成行内元素排版的时候,元素之间的空白符(空格、回车换行等)都会被浏览器处理。HTML代码中的回车换行被转成一个空白符,在字体不为0的情况下,空白符占据一定宽度
解决方案:
- 浮动
- 设置margin为负值
- 父元素font-size:0,子元素再设置实际值
- display:table和word-spacing
grid布局
网格布局:将容器划分成行和列,产生单元格,然后指定项目所在的单元格
容器属性
- display:grid 和inline-grid
grid-template-columns定义列宽,可以使用绝对单位,也可以使用百分比,也可以用一些关键字grid-template-rows定义行高grid-gap设置行间距和列间距grid-auto-flow项目放置顺序column rowjustify-items单元格内容水平对齐方式align-items单元格内容垂直对齐方式justify-content整个内容区域在容器里面的水平位置align-content整个内容区域的垂直位置
项目属性
grid-column-startgrid-column-endgrid-row-startgrid-row-endgrid-area属性指定项目放在哪一个区域 参考grid布局
display:flex,flex有几个属性值?
- flex-grow:项目放大比例
- flex-shrink:项目缩小比例
- flex-basis:在分配多余空间之前,项目占据的主轴空间
利用flex布局实现如下
align-self:属性允许单个项目有与其他项目不一样的对齐方式.
利用align-self属性,设置flex-end
transfrom:tranlate(0)
下列布局的结果如何
<div class='block'>
<div class='inner'></div>
</div>
.block{
position:relative;
width:100px;
height:100px;
transform:translate(0);
border: 1px solid #000;
}
.inner{
position:fixed;
width:100px;
height:100px;
top:50px;
left:50px;
background-color:#000;
}
使用CSS3的transform: translate(0, 0)转化位置节点,其所有使用position:fixed定位的子孙节点的定位功能均无效
重绘和回流
回流:对 DOM 结构的修改引发 DOM 几何尺寸变化
重绘:DOM 的修改导致了样式的变化,并且没有影响几何属性
canvas的宽高和css宽高有什么不同
- canvas 元素是
可替换元素, 有默认的宽高属性(此属性与 css 样式中的 width 和 height 不同), 默认300px*150px - canvas 的绘制宽高取决于它的宽高属性, 与 css 样式中的宽高无关
- css中的宽高指的是
展示宽度,会拉伸
canvas图片不清晰
根据像素比放大画布尺寸,然后显示的宽度不变
canvas画一个圆
语法:
ctx.arc(x, y, radius, startAngle, endAngle, Boolean)
圆心坐标: (x, y)
半径: radius
起始角度: startAngle
结束角度: endAngle
是否逆时针旋转: false 代表顺时针旋转
// 开始绘制路径
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle = 'red';
// 绘制圆的路径**
ctx.arc(100, 100, 50, 0, Math.PI * 2, false);
// 0°是从三点钟方向开始的
// 描边路径
ctx.stroke();
css3画半个圆,起始点是哪里
width:160px;
height:90px;
background-color: transparent;
border-bottom-right-radius: 90px;
border-bottom-left-radius: 90px;/*增加了边框,圆角半径也要变化*/
border-left: 10px solid black;/*边框左边线*/
border-right: 10px solid black;/*边框右边线*/
border-bottom: 10px solid black;/*边框底边线*/
echarts标签重叠
- 单行重叠:
avoidLabelOverlap:true - 多行重叠:
minShowLabelAngle设置最小显示角度;玫瑰图roseType:'area'
CSS3优化
- translate3d
- 尽量使用transform和opacity
- 尽可能少的使用box-shadows与gradients
transform和left top有什么区别
- top和left直接改变元素的
真实位置 - transform 只是改变了
视觉位置,元素本身位置没有改变 - 由于 transform 不改动 css 布局,因为渲染行为大多数情况下在元素本身,所以
效率比 top left 要高。
CSS 选择器解析顺序
从右往左解析,过滤掉一些无关的样式规则和元素,这样做是为了减少无效匹配次数,从而匹配快、性能更优。
CSS优化,提高性能的方法有哪些?
overflow
scroll内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。auto如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。
Javascript
undefined和null的区别
- null:代表空值,
空指针对象,表示该处不应该有值,typeof null=='object' (1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
- undefined:一个变量声明了未赋值,就是undefined (1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
扩展运算符
内部函数和闭包
内部函数:一般来说在一个函数内部定义另外一个函数,这样的函数就是内部函数。
闭包:能够读取其他函数内部变量的函数,能够让局部变量长久保存和共享,不会对全局变量造成污染
闭包的缺点:不断占用内存,导致内存泄漏
闭包的运用
普通的vue文件
data:{}
vue的脚手架里:
data{
return {}
}
为什么闭包不会被回收
JS的垃圾回收机制:当一个值的引用变量为0是,就会被垃圾回收机制回收
function foo(){
var a = 2;
function outer() {
a += 1;
console.log(a);
}
return outer
}
var baz = foo(); //在全局作用域下创建变量baz
baz指向的就是 outer,所以outer始终都没有被销毁,而根据垃圾回收机制,由于在outer中有引用外层函数的变量a,因此a也一直没有被销毁
经典面试题
var callbacks;
for(var i = 0 ; i <= 5 ;i ++) {
callbacks = function() {
console.log(i);
}
}
callbacks(); //6
callbacks(); //6
callbacks(); //6
简述下js事件代理(事件委托)以及它有什么缺点
事件代理:通过事件冒泡把一个元素的响应事件的函数代理到它的父层或者更外层元素上
缺点:
- 只能支持冒泡的事件,对于不冒泡的事件无法代理( focus/blur )
- 所有事件都代理容易出错,建议就近委托
- 内部元素层级过多,容易被某层阻止掉
怎么样判断对象的真实类型
Object.prototype.toString.call(val)instanceofconstructor
深拷贝和浅拷贝
- 简单的数据来说使用 JSON.stringify 和 JSON.parse 来实现
- 复杂的使用第三方库 Lodash
- 递归赋值
对于引用类型,浅拷贝就是增加了一个指针,指向同一个地址,浅拷贝就是只拷贝一层
解构运算符也是浅拷贝的一种,可用来处理一级数据
浅拷贝示例
function shallowClone(source) {
var target = {};
for(var i in source) {
if (source.hasOwnProperty(i)) {
target[i] = source[i];
}
}
return target;
}
深拷贝
function clone(source) {
if (!isObject(source)) return source;
var target = {};
for(var i in source) {
if (source.hasOwnProperty(i)) {
if (typeof source[i] === 'object') {
target[i] = clone(source[i]); // 注意这里
} else {
target[i] = source[i];
}
}
}
return target;
}
function isObject(x) {
return Object.prototype.toString.call(x) === '[object Object]';
}
JS的数据类型(内置类型)
基本类型:String,Number,Boolean,Null,Undefined,Symbol
引用类型:Object
1.typeof 能得到的结果:string number boolean object undefined function symbol
typeof null --> "object"
typeof undefined ---> "undefined"
typeof true | false ---> 'boolean'
typeof 42 ---> 'number'
typeof "42" ---> 'string'
typeof { name : '1'} | [] ---> 'object'
typeof Symbol ---> 'symbol'
typeof ()=>{} ---> 'function'
typeof void 0 ---> 'undefined'
2.instance of适合判断object类型的
var arr = [] ;
arr instanceof Array ---> true
null instanceof Object ---> false
[function] instanceof Object | Function --> true
Object.prototype.toString.call() 这种方式可以将全部的数据类型检测出来
Object.prototype.toString.call(null) ---> [object Null]
Object.prototupe.toString.call(undefined) ---> [object Undefined]
Object.prototype.toString.call(123) ---> [object Number]
Object.prototype.toString.call(true) ---> [object Boolean]
Object.prototype.toString.call('123') ---> [object String]
Object.prototype.toString.call({}) ---> [object Object]
Object.prototype.toString.call([]) ---> [object Array]
Object.prototype.toString.call(Math) ---> [object Math]
Object.prototype.toString.call(function(){}) ---> [object Function]
Objdec.prototype.toString.call(new Date) ---> [object Date]
Object.prototype.toString.call(Symbol()) ---> [object Symbol]
数组相关问题
ES6新增数组方法?
Array.from()、Array.of()、copyWithin()、find()、findIndex()
fill()、entries()、keys()、values()、includes()
forEach()、map()、filter()、some()、every()、indexOf()、
lastIndexOf()、reduce()、reduceRight()
向数组增加元素的方法
- push()尾部添加
- unshift()头部添加
- splice()指定位置增加/删除元素
- concat()
注意: concat和push两种增加元素的方式有什么不同?
push()会改变原数组,而concat()是返回一个新数组
数组里面有10万条数据,取第一个元素和第10万个元素哪个用时长?
用时基本上一样,因为 js 里面没有数组类型,数组其实也是一个对象,key 和 value。
数组去重
- set() 实现
function unique (arr) {
return Array.from(new Set(arr))
}
- 双重遍历循环实现
- 空 Object 实现和单层遍历实现
- 利用数组内置方法加单层遍历去重( indexOf、includes )实现
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array .indexOf(arr[i]) === -1) {
array .push(arr[i])
}
}
return array;
}
- Map 和单层遍历实现
- 数组 filter 方法实现
function unique(arr) {
return arr.filter(function(item, index, arr) {
//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
return arr.indexOf(item, 0) === index;
});
}
多维数组转一维数组
- 递归
let newArr = [] // 存放转化后的一维数组
function arrConversion (arr) {
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
arrConversion(arr[i])
} else {
newArr.push(arr[i])
}
}
}
- toString()+split()
- join()+split()
- flat()方法
- reduce()
apply()+concat()的方法
//apply方法会调用一个函数,apply方法的第一个参数会作为被调用函数的this值
//apply方法的第二个参数(一个数组,或类数组的对象)会作为被调用对象的arguments值
//也就是说该数组的各个元素将会依次成为被调用函数的各个参数
function reduceDimension(arr) {
return Array.prototype.concat.apply([], arr);
}
for in 和 for of 有什么区别?
for in一般用来遍历对象,遍历出的值是key
for of一般遍历数组、字符串等,遍历出的值是value
如何实现一个sleep函数(延迟函数)?
/**
* 延迟函数
* @param {Number} time 时间
*/
function sleep (time = 1500) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true)
}, time)
})
}
map和forEach的区别?
相同:遍历数组,匿名函数都支持3个参数,参数分别是item(当前每一项)、index(索引值)、arr(原数组)
区别:
- map()方法返回一个新数组
- map()方法不会改变原始数组
- map()方法不会对空数组进行检测
- forEach()方法用于调用数组的每个元素,将元素传给回调函数.
原型链和原型
从输入URL到页面响应,发生了什么?
- 域名解析:把域名解析成ip地址
1.先检查浏览器缓存
2.本机域名解析
3.DNS请求获取ip
- 网络请求
1.TCP三次握手(tls握手)
2.发送http请求
3.http响应
4.浏览器解析响应报文,渲染页面
5.TCP四次挥手
什么是Symbol?使用场景?
Symbol:表示独一无二的值
使用场景:
- 消除魔法字符
- 作为对象属性
const name = Symbol('name');
const obj = {
[name]: 'ClickPaas',
}
- 模拟类的私有方法
const speak = Symbol();
class Person {
[speak]() {
...
}
}
自己实现一个new方法
// ES5构造函数
let Parent = function (name, age) {
this.name = name;
this.age = age;
};
Parent.prototype.sayName = function () {
console.log(this.name);
};
const child = new Parent('听风是风', 26);
child.sayName() //'听风是风'
//ES6 class类
class Parent {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
console.log(this.name);
}
};
const child = new Parent('echo', 26);
child.sayName() //echo
JS继承
- 原型链继承
- 借用构造函数继承
- 组合继承
- 原型式继承
- 寄生式继承
- 寄生组合式继承
箭头函数与普通函数的区别
- 不能作为构造函数,不能使用new
- 箭头函数不绑定arguments,取而代之用rest参数...解决
- 箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值
- 箭头函数通过 call()或apply() 方法调用一个函数时,只传入了一个参数,对 this 并没有影响
this指向?
this指向调用它的那个对象
- 箭头函数this,定义函数时绑定的
- 如果是一般函数,this指向全局对象window
- 对象的方法里调用,this指向调用该方法的对象.
- 构造函数里的this,指向创建出来的实例.
原型和原型链
- 每个函数都有一个
prototype属性,指向函数的原型对象 - 每个对象都有一个
_propto_的属性,指向其构造函数的prototype - 每个原型都有一个
constructor属性,指向该关联的构造函数原型的作用
- 数据共享,节省内存空间,共享原型对象的属性和方法
- 为了实现继承
如何访问对象原型
1.person.__proto__===Person.prototype;// true
2.person.constructor.prototype===Person.prototype;// true
3.Object.getPrototypeOf(person)===Person.prototype;// true
创建对象的方式有哪些
1.对象字面量
let o={}
2.Object构造函数
let o=new Object()
o.name='a'
...
3.使用函数创建对象并返回(工厂模式)
function creactObj(name,age){
let p={
name:name,
age:age,
fn:function(){
console.log('hahaha')
}
}
return p
}
let newObj=createObj('aaa',18)
4.自定义构造函数
function Person() {
this.name = 'hanmeimei';
this.say = function() {
console.log(this.name)
}
}
var p = new Person();
5.原型
function Person(){}
Person.prototype={
name:'a',
age:10,
sayName: function(){
return this.name;
}
}
let p=new Person()
6.组合使用构造函数模式和原型模式
创建自定义类型是最常见方式,就是组合使用构造函数模式与原型模式。
构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。
结果每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度的节省了内存
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
}
Person.prototype = {
constructor: Person,
sayName: function () {
console.log(this.name);
}
}
7.ES6中用class创建 8.寄生
new操作实际执行了哪些操作
1.创建一个新的对象 var obj={}
2.this指向新创建的对象
3.执行构造函数中的代码
4.返回这个对象
obj.__proto__ = Constructor.prototype
解释一下Promise
Promise是ES6提供的一种异步解决方案, 它允许将写法复杂的传统回调函数和监听事件的异步操作, 用同步代码的形式将结果传达出来.链式调用
propmise的出现
promise的出现解决了嵌套回调的问题,支持多个并发
promise的状态
- pendding->等待
- fulfilled->执行
- rejected->拒绝
Promise是一个构造函数, 他需要通过
new实例化来使用, 实例化的同时 Promise内部的状态为初始的 pending,fn是一个回调函数,它的参数resolve、reject分别对应fulfilled、rejected
promise对象的方法
- then :resolve和reject结果的回调
reject时需要在then中多传入一个执行回调
const promise = new Promise((resolve, reject) => {
let value = 1 + 1
reject(value)
})
.then(function(res) {
console.log(res) // fulfilled 不会被调用
}, function(err) {
console.log(err) // 2
})
- catch捕获错误
只要前面出现错误就会转到catch函数,中间无论有多少个 then 都不会执行,
除非 then 中传入了失败的回调
Promise的静态方法
resolvePromise.resolve返回一个fullfill状态的promise对象all只有每个promise对象状态都为resolve才会调用, 通常用来处理多个并行异步操作racePromise.race只要其中某个元素先进入 fulfilled 或者 rejected 状态就会进行后面的处理(执行then)any只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态finally无论Promise返回的结果是什么都会执行 finally 并且 不会改变 Promise 的状态
JS垃圾回收机制
周期性运行以释放那些不需要的内存
引用计数法:如果没有引用指向该对象(引用次数为0),对象将被垃圾回收机制回收。
将对象赋值为null
标记清除法:对象是否可以获得,标记清除法假定存在一个根对象(相当于js的全局对象),垃圾回收器将定期从根对象开始查找,凡是从根部出发能扫描到的都会保留,扫描不到的将被回收
浏览器event loop?
JavaScript的最大特点是单线程
进程和线程
线程是cpu调度的最小单位,一个进程可以有多个线程进程是cpu资源分配的最小单位,能拥有资源和独立运行的最小单位 浏览器是多进程的,每个tab页就是一个进程,一个进程中可能包括渲染线程、JS 引擎线程、HTTP 请求线程等
事件机制
任务分为同步任务和异步任务,同步任务进入主线程,形成一个执行栈,异步任务进入任务队列。主线程中的任务执行完毕后会从事件队列中取出放入执行栈。
js的异步是通过回调函数实现的:
- 普通函数,click,resize
- 资源加载,onload,error
- 定时器,settimeout等
除了分同步异步之外,还分为宏任务和微任务
- 宏任务(macrotask)包括:主代码script,setTimeout,setInterval
- 微任务(microtask)包括:process.nextTick,Promise,MutationObserver
事件循环的执行顺序为
- 事件循环开始,script 代码块做为宏任务进入主线程执行
- 同步任务移入主线程执行,异步任务进入事件队列
- 主线程执行完成后,取出事件队列中的微任务执行
- 微任务执行完毕后,事件循环结束
- 取出事件队列中的宏任务,开始新一轮事件循环
webpack的打包流程
webpack是一个前端模块化打包工具,主要由入口,出口,loader,plugins四个部分。在 webpack 里一切文件皆模块,通过 loader 转换文件,通过 plugin 注入钩子,最后输出由多个模块组合成的文件。
webpack优化前端性能
- 压缩代码。
UglifyJsPlugin和ParallelUglifyPlugin来压缩JS文件, 利用mini-css-extract-plugin来压缩css - 利用CDN加速。在构建过程中,将引用的静态资源路径修改为CDN上对应的路径。可以利用 webpack 对于output 参数和各
loader的publicPath参数来修改资源路径。 - 删除死代码。将代码中永远不会走到的片段删除掉。JS 用
Tree Shaking,CSS 需要使用Purify-CSS - 提取公共代码。
CommonsChunkPlugin插件
webpack提高构建速度
- 多入口的情况,使用
CommonsChunkPlugin插件提取公共代码 - 通过
externals配置来提取常用库 - 利用
DllPlugin和DllReferencePlugin预编译资源模块, 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。 - 使用
Happypack实现多线程加速编译 - 使用
webpack-uglify-parallel来提升uglifyPlugin的压缩速度。 原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度. - 使用
Tree-shaking和Scope Hoisting来剔除多余代码
nodejs、容灾
罗列三种垂直水平居中的方法
实现一个数组的some()方法
Array.prototype.some = function (fn) {
if (typeof fn !== "function") {
throw new TypeError(`${fn} is not a function`)
}
for (let i = 0; i < this.length; i++) {
if (fn(this[i])) {
return true
}
}
return false
}
防抖和节流,手写一个节流
防抖:延迟执行,一段时间内多次点击,每次触发事件都重置定时器。
节流:间隔执行,每隔一段时间执行一次,定时器到时间后才清空。
防抖
function debounce(fn,delay){
let timer=null
return function(){
let context = this
let args = arguments
if(timer)clearTimeout(timer)
timer=setTimeout(()=>{
fn.apply(context,args)
},delay)
}
}
节流
function throttle(fn,delay){
let timer=null
return function(){
let contenxt=this
let args=arguments
if(!timer){
timer=setTimeout(()=>{
timer=null
fn.apply(context,args)
},delay)
}
}
}
应用场景
- 防抖:search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
- 节流:鼠标不断点击触发;监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
封装一个深拷贝的方法
function deepClone(obj){
if(!Object.proptotype.toString().call(obj)==='[Object Object]')return obj
let target={}
for(let i in obj){
if(obj.hasOwnProperty(i)){
if(typeof obj[i]==='obj'){
target[i]=deepClone(obj[i])
}else{
target[i]=obj[i]
}
}
}
}
堆和栈?
栈内存自动分配相对固定大小的内存空间,并由系统自动释放。用于存放基本类型和对象变量的指针.后进先出
堆内存是动态分配内存,内存大小不一,也不会自动释放。用于存放引用类型如object
闭包的删除?
作用域和作用域链
作用域:就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
全局作用域:在代码任何地方都能够访问到函数作用域:只在固定的一个区域能访问到,函数体内变量声明之前就已经可用块级作用域:块级作用域可通过新增命令 let 和 const 声明,所声明的变量在指定块的作用域外无法被访问
1.在一个函数内部
2.在一个代码块(由一对花括号包裹)内部
作用域链:
js声明变量的方法
let const var import function class
1.let、const、var区别?
| var | let | const |
|---|---|---|
| 无块级作用域 | 有块级作用域 | 有块级作用域 |
| 变量提升 | 无变量提升 | 无变量提升 |
| 可重复声明 | 同一作用域内不能重复声明 | 同一作用域内不能重复声明 |
- 什么是
变量提升?
函数声明和变量声明总是会被解释器悄悄地"提升"到方法体的最顶部,即提升到作用域的最顶上
- 什么是
暂时性死区? ES6规定,let/const命令会使区块形成封闭的作用域。若在声明之前使用变量,就会报错.
2.const定义常量可不可以修改?
const 定义基础类型是不可以修改的
const 定义引用类型是可以修改引用类型里面的值
JS常见的内存泄漏
- 闭包
- 被遗忘的计时器或回调函数
- DOM节点移除了,但是绑定的事件没有移除
ES6的proxy
如何判断两个对象是否相等
- 先判断两个是不是对象类型 instanceof
- 判断对象长度 Object.keys
- 判断对象相应的key值是否相同
- 判断俩个对象的相应的key对应的值是否相同
- 递归 参考
aaabbbcccddd计算每个字符的个数
根据对象的key值唯一的特点
function count(str){
let map=new Map()
for(let v of str){
if(map.has(v)){
num=parseInt(map.get(v)+1)
}else{
map.set(v,1)
}
}
let obj=Object.create(null)
for (let[k,v] of map) {
obj[k] = v;
}
console.log(obj)
}
axios原理
axios基于Promise对原生的XHR进行了全面的封装
Fetch
Fetch API 是一个用用于访问和操纵HTTP管道的强大的原生 API。fetch是作为XMLHttpRequest的替代品出现的。
使用fetch,你不需要再额外加载一个外部资源。但它还没有被浏览器完全支持,所以你仍然需要一个 polyfill
add(1,2)=add(1)(2)=3
function add(a){
if(arguments.length > 1){
return [...arguments].reduce((pre,val)=> pre+val, 0)
}else{
let ret = function(b){
a = a + b
return ret
}
ret.toString = function() { return a }
return ret
}
}
console.log(add(1,2,3));
console.log(add(1)(2)(3))
// 6
// f 6
CommonJS与ES6 Module
- commonjs是
运行时加载模块,ES6是在静态编译期间就确定模块的依赖 - ES6在编译期间会将所有import
提升到顶部,commonjs不会提升require; - commonjs是
module.exports,exports导出,require导入;ES6则是export导出,import导入 - commonjs导出的是一个
值拷贝,会对加载结果进行缓存,一旦内部再修改这个值,则不会同步到外部。ES6是导出的一个引用,内部修改可以同步到外部;
如何区别浮点数和整数
- parseInt之后看和原来的值是否相等
- 正则表达式
- Math.floor之后,看和原来的值是否相等
JS如何创建私有变量
构造函数
// 在构造函数内部定义了私有变量name
// 定义了特权方法getName setName
// 特权方法作为闭包有权访问name
// 每个实例的name都是独立的
// 每个实例的特权方法也是重新创建的,无法共享,这也是缺点所在
function Person(name) {
this.getName = function() {
return name;
};
this.setName = function(value) {
name = value;
}
}
var tc = new Person('tc');
var dj = new Person('dj');
tc.getName(); // tc
dj.getName(); // dj
静态私有变量
// 立即执行函数创建了一个私有作用域
// name为私有变量
// Person没有使用函数声明,而是函数表达式,是因为函数声明只能定义局部函数,在这里是定义私有方法才用的
// Person没有用var定义,默认为全局变量
// 特权方法定义在原型上,所以可以被实例共享
// 但是私有变量被所有实例共享,一个实例改变了私有变量,其他实例均受影响,所以这也是缺点
(function() {
var name = '';
Person = function(value) {
name = value;
};
Person.prototype.getName = function() {
return name;
};
Person.prototype.setName = function(value) {
name = value;
};
})();
var tc = new Person('tc');
tc.getName(); // tc
var dj = new Person('dj');
tc.getName(); // dj
参考