前端实习面试总结
文章目录HTML+CSS1.如何理解HTML语义化2. 哪些HTML是块级元素、内联元素(行内元素、行内块元素)3.盒模型的宽度和高度如何计算4.margin纵向重叠的问题5.margin负值的问题6.BFC的理解与应用7.float布局的问题8.清除浮动的方式9.flex画色子10.absolute和relative分别依据什么定位11.居中对齐实现有哪些方式12.line-height的继承问
HTML+CSS
1.如何理解HTML语义化
- 增加代码的可读性
- 让搜索引擎更容易读懂
2. 哪些HTML是块级元素、内联元素(行内元素、行内块元素)
-
块级元素:div、p、h1-h6、ul、ol、li
可以自动换行、设置宽高有效,margin和padding设置都有效
-
行内元素:span、strong、em
不可以自动换行,对margin上下无效,padding有效,设置宽高无效
-
行内块元素:input、img
不会自动换行,宽高、行高以及边距都可以设置
3.盒模型的宽度和高度如何计算
- 盒模型的宽度:左右内边距(padding)+左右边距(border)+width
- 盒模型的高度:上下内边距(padding)+上下边距(border)+height
- 若出现box-sizing,盒子实际高度和盒子实际宽度就是width和height
4.margin纵向重叠的问题
-
兄弟级的垂直块状之间,margin这个属性上下边距,会发生重叠的情况
解决办法:float浮动或display:inline-block
-
父子级的块之间,子级的上下margin会与父级上下margin重叠
解决办法:父级加overflow:hidden或加padding或加border,子级加position:absolute
5.margin负值的问题
- margin-top和margin-left负值,自身元素向上、向左移动
- margin-right负值,右侧元素左移,自身不受影响
- 如果margin-bottom负值,下方元素上移,自身不受影响
6.BFC的理解与应用
-
BFC 是 ( Block Fromatting Context ) 的简写,翻译过来是 块级格式化上下文 ,拥有 BFC 属性的盒子,将成为一个独立的区域,子元素不会影响到外面
-
BFC条件
float不为none的元素position为fixed和absolute的元素
display为inline-block、table-cell、table-caption,flex,inline-flex的元素
overflow不为visible的元素
7.float布局的问题
- 一种是元素的浮动导致的布局混乱的问题
- 另一种是浮动后的盒子模型塌陷问题。
8.清除浮动的方式
-
在浮动盒子的后面添加一个空盒子,对该空盒子添加CSS样式:clear: both;
-
对浮动的盒子父级添加该属性:overflow: hidden;(形成BFC)
-
在父元素内使用overflow:auto
-
添加伪类
after
,这种办法应该是现在主流清除浮动的方法
9.flex画色子
10.absolute和relative分别依据什么定位
- absolute:绝对定位;相对于父元素或者body进行定位,absolute 定位使元素的位置与文档流无关,因此不占据空间
- relative:相对定位;相对于当前位置进行定位,在使用相对定位时,无论是否进行移动,元素仍然占据原来的空间。
- fixed:固定定位;相对于浏览器的页面进行定位;
11.居中对齐实现有哪些方式
-
水平居中
inline元素 : text-align: center; block元素 : margin: auto; absolute元素 : left: 50%; margin-left: 负值;
-
垂直居中
inline元素 : line-height的值等于height的值 absolute元素 : top: 50%; margin-top: 负值; absolute元素 : transform : (-50%,-50%); absolute元素 : top left right bottom 全都为 0; margin: auto;
12.line-height的继承问题
-
写具体数值,如30px,直接继承该值
-
写比例,如2或1.5,则继承该比例
-
写百分比,如200%,则继承计算出来后的值
13.rem、px、em是什么
px:实际上就是像素,用PX设置字体大小时,比较稳定和精确。
rem:相对于根元素 <html>
,这样就意味着,我们只需要在根元素确定一个参考值。
em:就是根据基准来缩放字体的大小。
14.如何实现响应式
目的:为了网页能够兼容不同的终端
- 方案一:百分比布局(流式布局,就是百分比布局,也称为非固定像素布局)
- 方案二:felx弹性盒子布局(用来为盒状模型提供最大的灵活性。)
- 方案三:rem响应式布局
15.flex弹性盒子布局
-
flex:意为"弹性布局",用来为盒状模型提供最大的灵活性。
-
容器属性:
①
flex-direction
属性:决定主轴的方向(即项目的排列方向);②
flex-wrap
属性:规定如果一条轴线排不下,如何换行;③
flex-flow
属性:是flex-direction
属性和flex-wrap
属性的简写形式,默认值为row/nowrap
;④
justify-content
属性:定义了项目在主轴上的对齐方式;⑤
align-items
属性:定义项目在交叉轴上如何对齐;⑥
align-content
属性:定义了多根轴线的对齐方式;
变量类型和计算
1.typeof能判断哪些类型
- 可以判断出所有的值类型,但是null判断结果为object
- 引用类型:function判断结果为function,数组、对象等判断结果都是为object
2.何时使用=何时使用
===判断值和类型是不是一样的,==判断值是不是一样的
3.值类型和引用类型的区别
-
存储位置不一样
值类型是存储在栈中,而引用类型变量存储在栈中,变量对应的是值是值的地址,而它的值是存储在堆中
-
复制方式不一样
值类型:在将一个保存着原始值的变量复制给另一个变量时,会将原始值的副本赋值给新变量,此后这两个变量是完全独立的
引用类型:引用类型进行复制的时候,只是会把这个内存地址赋值给新变量, 两个变量的值还是同一个,改变值的时候,另一变量的值也会改变
-
值类型无法添加属性和方法,引用类型可以添加属性和方法
-
值类型的比较是值的比较,只有当它们的值相等的时候它们才相等,引用类型的比较是引用地址的比较
4.手写深拷贝
-
注意判断值类型和引用类型
-
判断是数组还是对象
-
递归
function deepClone(obj = {}) { if (typeof obj !== 'object' || obj == null) { // obj 是 null ,或者不是对象和数组,直接返回 return obj } // 初始化返回结果 let result if (obj instanceof Array) { result = [] } else { result = {} } for (let key in obj) { // 保证 key 不是原型的属性 if (obj.hasOwnProperty(key)) { // 递归调用!!! result[key] = deepClone(obj[key]) } } // 返回结果 return result }
5.null和undefined的区别
- 定义不同:null就是表示空值,而undefined表示的是未定义
- Number转换的值不同,Number(null)输出为0, Number(undefined)输出为NaN
- undefied和null进行比较时,使用 == 判断的结果为真,null 和 undefined 的值相等,使用 ===判断的结果为false,类型不等
6.变量声明提升
-
函数提升优先级高于变量提升
-
console.log(a); var a = 3; //预编译后的代码结构可以看做如下: var a; // 将变量a的声明提升至最顶端,赋值逻辑不提升。 console.log(a); // undefined a = 3; // 代码执行到原位置即执行原赋值逻辑
-
即函数提升只会提升函数声明(函数提升是可以直接在函数声明之前调用该函数,并能成功执行它),而**不会提升函数表达式(函数表达式就可以看作成变量提升)。
console.log(foo1); // [Function: foo1]
foo1(); // foo1
console.log(foo2); // undefined
foo2(); // TypeError: foo2 is not a function
function foo1 () {
console.log("foo1");
};
var foo2 = function () {
console.log("foo2");
};
//预编译后的代码结构可以看做如下:
var foo1 = function () {
console.log('foo1');
};
console.log(foo1);
foo1();
var foo2;
console.log(foo2);
foo2();
foo2 = function () {
console.log('foo2');
};
原型和原型链
1.原型
- 所有的引用类型(数组、对象、函数)都有一个_proto_ 属性(隐式原型属性)
- 所有的函数,都有一个 prototype(显式原型)属性
- 所有引用类型,它的_proto_属性指向它的构造函数的prototype属性。
2.原型链
当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去,也就是我们平时所说的原型链的概念,Object.prototype->原型链的终点为 null
3.如何准确判断一个变量是不是数组
-
通过Array.isArray()
Array.isArray()能判断一个元素是否为数组,如果是就返回true,否则就返回false
-
通过instanceof判断
-
通过对象构造函数的constructor判断
4.class的原型本质,怎样理解
class是es6的新特性之一,它的本质就是一个函数,可以通过constructor构造方法来构造一些属性,定义方法时,不需要加function,方法之间也不需要逗号隔开,然后可以通过new关键字来实例化这个类
5.class与继承
- 作用:子类可以继承父类构造函数的属性和方法
- 怎么做:子类可以通过extends和super关键字来继承父类
6.构造函数和普通函数的区别
-
构造函数也是一个普通函数,创建方式和普通函数一样,但构造函数习惯上首字母大写
-
构造函数和普通函数的区别在于:调用方式不一样。作用也不一样(构造函数用来新建实例对象)
-
调用方式不一样。
a. 普通函数的调用方式:直接调用 person();
b.构造函数的调用方式:需要使用new关键字来调用 new Person();
-
构造函数内部用this 来构造属性和方法
-
返回值方面,对于构造函数而言,如果返回值是基本数据类型,那么返回值就是this指向的实例;如果是复杂数据类型,那么返回值为对象,而普通没有返回值,输出为undefined
7.构造函数和class的区别
1.类的内部所有定义的方法,都是不可枚举的(但是在es5中prototype的方法是可以进行枚举的)
2.类的构造函数,不使用new是没法调用的,会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行
3.Class不存在变量提升(hoist),这一点与ES5完全不同
4.ES5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。
作用域和闭包
1.this的应用场景,如何取值
this取什么值,是在函数执行的时候确定的,不是在函数定义的时候确定
- 在一般函数方法中使用 this 指代全局对象
- 作为对象方法调用,this 指代上级对象
- 作为构造函数调用,this 指代new 出的对象
- apply 调用 ,apply方法作用是改变函数的调用对象,此方法的第一个参数为改变后调用这个函数的对象,this指代第一个参数
2.手写bind函数
前端面试之手写一个bind方法_明月如霜丶-CSDN博客_手写bind
3. 作用域链
-
在 Javascript 中,作用域分为 全局作用域 和 函数作用域
-
全局作用域和函数作用域
全局作用域:代码在程序的任何地方都能被访问,window 对象的内置属性都拥有全局作用域。
函数作用域:在固定的代码片段才能被访问
-
作用域链:
一般情况下,变量取值到创建 这个变量 的函数的作用域中取值。但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
4.闭包
-
闭包是指有权访问另外一个函数作用域中的变量的函数,创建闭包的常见方式,就是在一个函数内部创建另外一个函数
-
优点:
① 减少全局变量。
② 减少传递函数的参数
③ 封装;
-
缺点:
使用闭包会占有内存资源,过多的使用闭包会导致内存溢出等. -
内存泄漏,说说你的解决方法
简单的说就是把那些不需要的变量,但是垃圾回收又收不走的的那些赋值为null,然后让垃圾回收走;
5.实际开发中闭包的应用场景
主要是用来封装变量。即把变量隐藏起来,不让外面拿到和修改。
异步
1.同步和异步的区别
- 同步:发送方发出请求后,等到服务器返回结果,才可以继续执行下一步
- 异步:是一种并行处理的方式,不必等待一个程序执行完,可以执行其它的任务
2.Promise
Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法。
3.前端使用异步的场景
- 定时任务:setTimeout, setInverval
- 网络请求: ajax请求、动态img加载
- 事件绑定
DOM
1.DOM模型结构
2.attribute和property的区别
-
property是DOM中的属性,是JavaScript里的对象;
-
attribute是HTML标签上的特性,它的值只能够是字符串;
3.查找、添加、删除、移动DOM节点的方法
-
创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点 -
添加、移除、替换、插入
appendChild() //添加
removeChild() //移除
replaceChild() //替换
insertBefore() //插入 -
查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性
事件
1.编写一个通用的事件监听函数
2.事件代理(委托)是什么?
事件委托是利用事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。
2.描述事件冒泡的流程
是指从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序,并存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段
-
事件捕获
捕获型事件(event capturing):事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定) -
事件冒泡
冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。
3.阻止事件冒泡
当你发父类也有同样类型的方法,但你在调用子类方法的时候不想触发父类方法的时候要阻止冒泡
- 方式一:event.stopPropagation();
$("#div1").mousedown(function(event){
event.stopPropagation();
});
- 方式二:return false;
$("#div1").mousedown(function(event){
return false;
});
但是这两种方式是有区别的。return false 不仅阻止了事件往上冒泡,而且阻止了事件本身。event.stopPropagation() 则只阻止事件往上冒泡,不阻止事件本身。
Ajax
AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
1.实现ajax的步骤
①创建 Ajax 核心对象(XMLHttpRequest)
②通过 Ajax 核心对象的 open() 方法建立与服务端的链接
③构建请求的数据内容,通过核心对象的 send() 方法发送给服务端
④通过核心对象提供的 onreadystatechange 事件,监听服务端的通信状态
⑤接受处理服务端响应的结果
⑥将结果更新到页面
2.Ajax中get和post的区别
Get请求的参数都在url里,所以send函数发送的参数为null,而Post请求在使用send方法时,却需赋予其参数;
使用Get请求时,参数在URL中显示,而使用Post请求,则不会显示出来;
Get请求请求需注意缓存问题,Post请求不需担心这个问题;
3.Ajax的应用
-
注册时,输入用户名自动检测用户是否已经存在。
-
登陆时,提示用户名密码错误
4.跨域
跨域:跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。
5.解决跨域的方法
-
JSONP跨域
JSONP包含两部分:回调函数和数据。
回调函数是当响应到来时要放在当前页面被调用的函数。
-
跨域资源共享(CORS)
CORS背后的思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
-
websocket
-
nginx代理跨域
-
postMessage
-
Node jS中间件代理
存储
1.cookie和session的区别
-
cookie数据存放在客户的浏览器上,session数据放在服务器上。
-
cookie不是很安全,别人可以分析存放在本地的COOKIE;考虑到安全应当使用session。
-
session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能;考虑到减轻服务器性能方面,应当使用COOKIE。
-
单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie
2.描述cookie、localStorage、sessionStorage的区别
HTML5的WebStorage提供了两种API:localStorage(本地存储)和sessionStorage(会话存储)。
-
相同点:都存储在客户端
-
存储大小:cookie传输数据4k左右,而localStorage、sessionStorage传输数据5M左右
-
有效时间:
cookie在设置的时间的过期之前,一直都是有效的;
localStorage:存储持久数据,浏览器窗口关闭以后数据不丢失,除非主动删除
sessionStorage:数据在浏览器窗口关闭以后,就自动删除
-
数据与服务器之间的交互方式
cookie:cookie的信息是往返客户端和服务器端的
sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
http
1.http常见的状态码有哪些
- 100-199消息:代表请求已被接受,需要继续处理
- 200-299成功:200 – 请求成功
- 300-399重定向:301 – 资源(网页等)被永久转移到其它URL;302 - 暂时重定向;304 - 没有修改
- 400-499请求错误:页面代码可能有误
- 500-599服务器错误:500 – 内部服务器错误;502 - 网关错误;503 - 服务不可用
2.http常见的header有哪些
3.描述一下http的缓存机制
缓存是网络传输中常用到的一种技术,利用缓存可以让我们在数据传输方面更加的方便和快捷
我们处理缓存的时候大致可以分为七步:接收
,解析
,查询
,新鲜度检验
,创建响应
,发送
,日志
4.get和post的区别
- 语义
GET:获取数据;POST:创建数据
- 缓存
GET可以被缓存
POST不会被缓存
- 发送数据
GET通过地址在请求头中携带数据
POST既可以通过地址在请求头中携带数据,也可以通过请求体携带数据
携带少量数据采用GET请求,携带大量数据采用POST请求
- 安全性
一般来说GET是不安全的,POST是安全的;
GET和POST都不安全
5.http传输过程
DNS解析
TCP连接
发送HTTP请求
服务器处理请求并返回HTTP报文
浏览器解析渲染页面
连接结束
6.页面渲染
1.解析HTML文件,创建DOM树
2.解析CSS,形成CSS对象模型
3.将CSS与DOM合并,构建渲染树(renderingtree)
4.布局绘制
7.说一下http和https
- http:超文本传输协议,是一个客户端和服务器端请求和应答的标准
- https:是http的安全版,https的安全基础就是SSL(安全套接字协议),https的主要作用是建立一个信息安全通道,来确保数据的传输,确保网站的真实性
8.http和https的主要区别
- https协议需要ca证书,费用较高
- http得信息是明文传输,https是具有安全性的SSL加密传输协议
- http协议的端口:80;https协议的端口:443
- http的连接简单,是无状态的
ES6
1.ES6新增的性能
-
新增了块级作用域(let,const)
ES6中是没有块级作用域的,并且var有变量提升,在let中,使用的变量一定要进行声明 -
新增了箭头函数。
ES6中的函数定义不再使用关键字function(),而是利用了()=>来进行定义 -
模板字符串
模板字符串是增强版的字符串,用反引号(`)标识,可以当作普通字符串使用,也可以用来定义多行字符串 -
class 类的继承
-
promise
Promise是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理、强大
-
Symbol
Symbol是一种基本类型。Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的
-
set和map数据结构
Set:类似于数组,只不过其成员值都是唯一的,没有重复的值。
Map:类似于对象,也是键值对集合,但是”键”的范围不限于字符串,对象也可以当作键
Vue
1.Vue的生命周期
Vue 实例从创建到销毁的过程,就是生命周期
2. vue生命周期的作用是什么
它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。
3.vue生命周期总共有几个阶段
它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeDestroy
- destroyed
4.Vue的数据双向绑定原理
-
vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的,其中比较关键的是数据劫持
-
第一步:需要observe的数据对象进行递归遍历, 包括子属性对象的属性,都加上setter和getter,这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
第二步:compile解析模板指令, 将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
第三步:Watcher订阅者是Observer和Compile之间通信的桥梁, 主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,
达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
5.Vue组件最常用的通讯方式
组件的作用:组件是自定义元素,可扩展html元素,封装可复用的代码。
主要分为两类:
-
父子组件间的传值
父组件向子组件传值
props、使用 c h i l d r e n 获 取 子 组 件 和 父 组 件 对 象 、 使 用 children获取子组件和父组件对象、使用 children获取子组件和父组件对象、使用ref获取指定的子组件
子组件向父组件传值
使用 e m i t 传 递 事 件 给 父 组 件 , 父 组 件 监 听 该 事 件 ; 使 用 emit传递事件给父组件,父组件监听该事件;使用 emit传递事件给父组件,父组件监听该事件;使用parent.获取父组件对象,然后再获取数据对象
-
非父子组件间的传值
1.事件总线
原理上就是建⽴立⼀一个公共的js⽂文件,专⻔门⽤用来传递消息
2.$sttrs/listeners 用于多级组件间传值的问题
3.vuex
6.MVVM
mvvm是 Model-View-ViewModel 的缩写,即 模型-视图-视图模型
Model:数据模型,后端传递的数据。
View:主要就是向用户展示信息的
ViewModel:数据监听与绑定,View与Model之间通信的桥梁
ViewModel 有两个方向(这两个方向都实现的,我们称之为数据的双向绑定)
- 将 Model 转化成 View ,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。
- 将 View 转化成 Model ,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听
webpack
1.webpack常见性能优化
2.webpack如何实现懒加载
3.前端代码为什么要打包
- 代码层面:
体积更小(Tree-shaking、压缩、合并),加载更快
编译高级语言和语法(TS、ES6、模块化、scss)
兼容性和错误检查(polyfill,postcss,eslint)
- 研发流程层面:
统一、高效的开发环境
统一的构建流程和产出标准
集成公司构建规范(提测、上线)
高频面试题
1.var和let、const的区别
-
let、const声明的变量仅在块级作用域内有效,var 声明变量是全局的,没有块级作用域功能
-
let 、const 不存在变量提升 , var 存在变量
-
let 、const不能在同一块级作用域内重复申请
2.typeof返回哪些类型
typeof的返回值共有七种:number, boolean, string, undefined, object, function,symbol.
3.列举强制类型转换和隐式类型转换
-
强制:
①Number(参数)把任何类型转换成数值类型
②parseInt(参数1,参数2)将字符串转换成整数
③parseFloat()将字符串转换成浮点数字
④string(参数):可以将任何类型转换成字符串
⑤Boolean()可以将任何类型的值转换成布尔值
-
隐式:
①四则运算:
加法运算符+是双目运算符,只要其中一个是string类型,表达式的值便是一个String。
对于其他的四则运算,只有其中一个是Number类型,表达式的便是一个Number。
对于非法字符的情况通常会返回NaN:‘1’‘a’ // => NaN,这是因为parseInt(a)值为NaN,1NaN还是NaN
②判断语句
判断语句中的判断条件需要是 Boolean类型,所以条件表达式会被隐式转换为Boolean。
4.split()和join()的区别
-
Split()方法是切割成数组的形式
-
Join()方法是将数组转换成字符串。
5.数组的pop、push、unshift、shift分别做什么
-
array.pop()
移除数组的最后一项,并返回移除项
-
array.push(value)
在数组末尾添加一项并返回新数组长度,value可以是任何类型
-
array.shift()
移除数组首项,并返回移除项
-
array.unshift(value)
在数组首项插入一项并返回新数组长度,value可以是任何类型
6.数组slice和splice的区别
- slice()方法可以从已有的数组中返回选定的元素。
array.slice(start,end)
①start 必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数 第二个元素,以此类推。
②end 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。
- splice() 方法可以用于插入、删除或是替换数组的元素。
splice删除:array.splice(1,2)
(删除array中的1、2两项);
splice插入:array.splice(1,0,'brown','pink')
(在array键值为1的元素前插入两个值);
splice替换:array.splice(1,2,'brown','pink')
(在array中替换1、2元素)
7.函数call和apply的区别
call和apply 都是用来修改函数中this的指向问题;
- apply()方法传入两个两个参数:一个是作为函数上下文的对象,另一个是作为函数参数所组成的数组。
- call()方法第一个参数也是作为函数上下文的对象,但是后面传入的是一个参数列表,而不是单个数组。
8.解释jsonp的原理,为何它不是真正的ajax
-
jsonp的原理:就是利用浏览器可以动态地插入一段js并执行的特点完成的。
-
ajax的核心是通过xmlHttpRequest获取非本页内容
jsonp的核心是动态添加script标签调用服务器提供的js脚本 -
jsonp只支持get请求,ajax支持get和post请求
9.document load和ready的区别
-
load是当页面所有资源全部加载完成后(包括DOM文档树,css文件,js文件,图片资源等),执行一个函数
问题:如果图片资源较多,加载时间较长,onload后等待执行的函数需要等待较长时间,所以一些效果可能受到影响
-
$(document).ready()是当DOM文档树加载完成后执行一个函数 (不包含图片,css等)所以会比load较快执行
在原生的jS中不包括ready()这个方法,只有load方法就是onload事件
10.new Object()和Object.create()的区别
- new Object()
①new是js中的操作符,可以创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。
②语法: new constructor ( [aguments] )
③由此我们可以看出,实际new创建对象,就是调用构造函数来实例化,在调用构造函数的时候会执行以下操作:
- 创建一个新的对象
- 将新对象执行原型操作,指向构造函数的原型
- 将this绑定到新对象上(可以使用call强制转换执行环境)
- 构造函数返回的对象就是实例化的结果,如果构造函数没有显示返回一个对象,则返回新的对象
- Object.create()
①Object.create()是Object的内置方法,可以创建一个新对象,使用现有的对象来提供新创建的对象__proto__
②语法:Object.create ( proto, [ propertiesObject ] )
③该方法有两个参数,第一个proto是一个对象,作为新建对象的原型;第二个参数是一个对象,该对象的属性名称是新创建的对象的属性名称。使用该方法,创建对象会执行以下步骤:
- 方法内部定义一个新的空对象obj
- 将obj.__proto__的对象指向传入的参数proto
- 返回一个新的对象
11.如何用JS实现继承
1.原型链
2.借用构造函数
3.组合继承
4.原型式继承
5.寄生式继承
6.寄生组合式继承
12.如何捕获JS程序中的异常
-
try…catch 用来异常捕获(主要适用于IE5以上内核的浏览器,也是最常用的异常捕获方式)
-
使用onerror时间捕获异常
13.什么是JSON
JSON是一种取代XML的数据结构,和xml相比,它更小巧但描述能力却不差,由于它的小巧所以网络传输数据将减少更多流量从而加快速度。语法:{"name":"admin","age":18}
json是一种纯字符数据,不属于编程语言
json的语法与js中object的语法几乎一致
json数据以键值对形式存在,多个键值对之间用逗号,隔开,键值对的键和值之间用冒号:连接
json数据在js对象的基础上做了严格化
json的数据可以用花括号{}或中括号[]包裹,对应js中的object和array
14.获取当前页面url参数
【正则匹配】、【拆分字符串成数组】、【新API URLSearchParams】三种方式获取参数
15.数组去重
// 最简单数组去重法
/*
* 新建一新数组,遍历传入数组,值不在新数组就push进该新数组中
* IE8以下不支持数组的indexOf方法
* */
function uniq(array){
var temp = []; //一个新的临时数组
for(var i = 0; i < array.length; i++){
if(temp.indexOf(array[i]) == -1){
temp.push(array[i]);
}
}
return temp;
}
var aa = [1,2,2,4,9,6,7,5,2,3,5,6,5];
console.log(uniq(aa));
16.前端性能如何优化?一般从哪几个方面考虑
- JavaScript 压缩和模块打包
其中之一就是可以得到更快的启动时间
其中之二是模块打包用于将不同脚本打包在一起并放进同一文件。更少的HTTP请求和单个文件解析都可以减少加载时间。通常情况下,单独一种工具就可以打理打包和压缩。webpack就是其中之一。 - 按需加载资源
资源(特别是图片)的按需加载或者说惰性加载,可以有助于你的web应用在整体上获得更好的性能。对于使用大量图片的页面来说惰性加载有着显著的三个好处。
算法
排序算法
冒泡排序
- 相邻之间相比较,左边比右边大的话,交换位置
- 实现代码
function sort(arr) {
for(let i = 0, l = arr.length - 1; i < l; i++) {
for(let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j+1]) {
[arr[j], arr[j+1]] = [arr[j+1], arr[j]]
}
}
}
}
let list = [5,4,8,2,1,9,7,3,6]
sort(list)
console.log(list)
快速排序***
- 找一个基准点(一般是中间数)
- 和基准值比较,比基准值小放leftList,比基准值大放rightList
- 递归执行上述操作,直到arr.length <= 1
function quickSort(arr){
if(arr.length<1){
return arr;
}
var pivotIndex=Math.floor(arr.length/2);//找到那个基准数
var pivot=arr.splice(pivotIndex,1)[0]; //取出基准数,并去除,splice返回值为数组。
var left=[];
var right=[];
for(var i=0;i<arr.length;i++){
if(arr[i]<pivot){
left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
return quickSort(left).concat([pivot],quickSort(right)); //加入基准数
}
arr=[2,1,5,8,3,7,4,6,9];
console.log(quickSort(arr)); //[1, 2, 3, 4, 5, 6, 7, 8, 9]
选择排序***
1,找到数组中最小值的索引
2,把最小值排到第一位来。以此类推
function selectionSort(arr) {
var len = arr.length;
var minIndex, temp;
for (var i = 0; i < len - 1; i++) {
minIndex = i;
for (var j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) { // 寻找最小的数
minIndex = j; // 将最小数的索引保存
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
插入排序
类似我们打扑克牌,牌从左向右的排序,抽出一张牌插到合适的位置放。
希尔排序
- 按一定的间隔对数组进行分组,一般以数组长度一半 gap = length / 2 (ps:也可以是3,4,无强性要求)
(假如:数组长度为10的话gap = 10 / 2 = 5,也就是,位置0和5为一组,位置1和6位一组…,组里的值进行插入排序) - 以gap的一半进行缩小 gap = gap / 2
(此时:gap = Math.floor(5 / 2) = 2 向下取整,也就是,位置0和位置2为一组,位置1和3为一组…,组里的值进行插入排序) - 当gap === 1时,此时所有元素为一组,此时运行的就是我们一般的插入排序了。
这样处理的好处是:希尔排序的优化使得原本 O(n^2) 的时间复杂度一下降为 O(nlogn)
归并排序***
采用分治思想,分治法将问题分(divide)成一些小的问题然后递归求解,而**治(conquer)**的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之
let dat=[5, 8, 10, 3, 2, 18, 17, 9];
function merge(left,right){
var temp=[];
while(left.length&&right.length){
if(left[0]<right[0]){
temp.push(left.shift());
}else{
temp.push(right.shift());
}
}
//left和right长度不一样时,直接连接剩下的长的部分(本身有序)
return temp.concat(left,right);
}
function mergeSort(data){
if(data.length<=1){
return data;
}
var mid=Math.floor(data.length/2);
var left=data.slice(0,mid);
var right=data.slice(mid);
return merge(mergeSort(left),mergeSort(right));
}
var sortedData=mergeSort(dat);
console.log(sortedData);
堆排序
- 构建堆,堆顶是最大的元素(子结点的键值或索引总是小于(或者大于)它的父节点)
- 把最大的元素交换到堆顶,然后把堆顶跟交换到数组后面,数组减1,依次重复。
桶排序
采用分治思想(ps:把数组分成若干小份,排好每小份,在拼接起来)
- 定义一个桶的大小(一个桶能装下几个值)
- 根据数组的长度,计算需要几个桶,每个桶都是小的数组,组成二维数组
- 往桶里放数据
- 每个桶的数组使用插入排序
- 把每个桶的数据拼接起来
计数排序
- 找出最大和最小元素。
- 统计每个元素出现的次数,以元素的值为索引,次数为value。
- 对所有计数开始累加,从min开始,每一项和前一项相加(加起来最后一个的值是数组的长度,用于下一步值的填充)
- 反向填充目标数组,将每个元素i放在新数组的第C[i]项,每放一个元素,计数-1
基数排序
- 先按排序个位数,以各位的值为key, 这个的值为value, 进行按各位的排序
- 排好个位数后,用排好的数组在按十位数排,以十位数的值为key, 这个值为value, 进行按十位的排序,依次类推
推荐排序算法博客前端十大经典算法 - SegmentFault 思否
查找算法
二分查找(折半查找)***
将要查找的值每次与中间值比较,大于中间值,则在右边进行相同的查找,小于中间值则在左边进行比较查找,找到返回索引值,没找到返回-1
顺序查找
从数组的首个元素开始,逐个匹配数组元素和查找目标,若找到,返回找到的元素索引,若遍历完没有找到,则返回-1。
更多推荐
所有评论(0)