五、rem 和flex布局原理
1.rem是根据html的font-size大小来变化,正是基于这个出发,我们可以在每一个设备下根据设备的宽度设置对应的html字号,从而实现了自适应布局
2.采用flex布局的元素,称为flex容器,它的所有子元素自动成为容器成员,称为flex项目。如下图:
容器默认存在2根轴,水平的主轴和垂直的侧轴,主轴的开始位置(与边框的交叉点)叫做main
start, 结束位置叫做 main
end.
交叉轴的开始位置叫做 cross start,结束位置叫做cross end。项目默认沿主轴排列。单个项目占据的主轴空间叫做main
size,
占据的交叉轴空间叫做cross size。
二:容器有如下6个属性
flex-direction
flex-wrap
flex-flow
justify-content
align-items
align-content
1.
flex-direction:该属性决定主轴的方向(即项目的排列方向)。
它可能有四个值:
row(默认值):主轴为水平方向,起点在左端。
row-reverse:主轴为水平方向,起点在右端。
column:主轴为垂直方向,起点在上沿。
column-reverse:主轴为垂直方向,起点在下沿。
六、什么是原型链 闭包js的内存分配机制
原型链:若访问对象属性时,先在基本属性中找,如果自身没有该属性,便会沿着_proto_这条链往上找这个找的路径叫原型链。
闭包:就是能够读取其他函数内部变量的函数。
由于在javascript中,只有函数内部的子函数才能读取局部变量,所以说,闭包可以简单理解成“定义在一个函数内部的函数“。所以,在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
原型链用于实现JS中的实现继承。(许多语言都支持两种方式的继承:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。由于函数没有签名,在ECMAScript中只能实现实现继承。
原型链作为实现继承的主要方法,其基本思想是利用原型让一个引用类型继承另一个引用继承的属性和方法。了解一下构造函数、原型和实例的关系:每个构造函数都是一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。假如我们让原型对象等于另一个类型的实例,那么此时的原型对象将包含一个指向另一个原型的指针,相应的另一个原型中包含着一个指向另一个构造函数的指针。如此层层递进,就构成了实例与原型的链条。这就是原型链的概念。
当函数调用时,需查找和获取的变量和元素都会通过原型链机制一层层的往上搜索在原型对象或继承来的对象中获得。
当函数被创建,就有了作用域,当被调用时,就有了作用域链,当被继承时就有了原型链,当需要获取作用域链或原型链上的变量或值时,就有了闭包
JS的内存分配:
javascript中的变量分为两种,原始值和引用值。
原始值:指的是原始数据类型的值,比如undefined,null,number,string,boolean类型所表示的值。
引用值:指的是复合数据类型的值,即Object,Function,Array等。
原始值和引用值存储在内存中的位置分别为栈和堆。
原始值是存储在栈中的简单数据段,他们的值直接存储在变量访问的位置。
引用值是存储在堆中的对象。
存储在栈中的值是一个指针,指向存储在堆中的实际对象。
八、前端性能优化思路经验
网页内容
服务器
Cookie
CSS
Javascript
图片
九、给一个已知数组去重
第一种是比较常规的方法
思路:
1.构建一个新的数组存放结果
2.for循环中每次从原数组中取出一个元素,用这个元素循环与结果数组对比
3.若结果数组中没有该元素,则存到结果数组中
Array.prototype.unique1 = function(){
var res = [this[0]];
for(var i = 1; i < this.length; i++){
var repeat = false;
for(var j = 0; j < res.length; j++){
if(this[i] == res[j]){
repeat = true;
break;
}
}
if(!repeat){
res.push(this[i]);
}
}
return res;
}
var arr = [1, 'a', 'a', 'b', 'd', 'e', 'e', 1, 0]
alert(arr.unique1());
第二种方法比上面的方法效率要高
思路:
1.先将原数组进行排序
2.检查原数组中的第i个元素 与 结果数组中的最后一个元素是否相同,因为已经排序,所以重复元素会在相邻位置
3.如果不相同,则将该元素存入结果数组中
复制代码代码如下:
Array.prototype.unique2 = function(){
this.sort(); //先排序
var res = [this[0]];
for(var i = 1; i < this.length; i++){
if(this[i] !== res[res.length - 1]){
res.push(this[i]);
}
}
return res;
}
var arr = [1, 'a', 'a', 'b', 'd', 'e', 'e', 1, 0]
alert(arr.unique2());
第二种方法也会有一定的局限性,因为在去重前进行了排序,所以最后返回的去重结果也是排序后的。如果要求不改变数组的顺序去重,那这种方法便不可取了。
第三种方法(推荐使用)
思路:
1.创建一个新的数组存放结果
2.创建一个空对象
3.for循环时,每次取出一个元素与对象进行对比,如果这个元素不重复,则把它存放到结果数组中,同时把这个元素的内容作为对象的一个属性,并赋值为1,存入到第2步建立的对象中。
说明:至于如何对比,就是每次从原数组中取出一个元素,然后到对象中去访问这个属性,如果能访问到值,则说明重复。
复制代码代码如下:
Array.prototype.unique3 = function(){
var res = [];
var json = {};
for(var i = 0; i < this.length; i++){
if(!json[this[i]]){
res.push(this[i]);
json[this[i]] = 1;
}
}
return res;
}
var arr = [112,112,34,'你好',112,112,34,'你好','str','str1'];
alert(arr.unique3());
let、var、const区别:
- const定义的变量可以修改,不可重复定义,而且必须初始化
2. var定义的变量可以修改,如果不初始化会输出undefined,不会报错。
3. let是块级作用域,函数内部使用let定义后,对函数外部无影响。
Promise:
Promise是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理更强大。
所谓Promise
,简单说就是一个容器,里面保存着某个未来才会结束的事件 (通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。
Promise
对象有以下2个特点:
1.对象的状态不受外界影响。Promise
对象代表一个异步操作,有三种状态:Pending(
进行中
)
、Resolved(
已完成
)
和Rejected(
已失败
)
。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise
这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
2.一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise
对象的状态改变,只有两种可能:从Pending
变为Resolved
;从Pending
变为Rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise
对象田静回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
有了Promise
对象,就可以把异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise
对象提供了统一的接口,使得控制异步操作更加容易。
跨域:
什么是跨域?
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。
所谓同源是指,域名,协议,端口均相同,
浏览器执行javascript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。
解决办法:
1、JSONP:
使用方式就不赘述了,但是要注意JSONP只支持GET请求,不支持POST请求。
2、代理:
例如www.123.com/index.html需要调用www.456.com/server.php,可以写一个接口www.123.com/server.php,由这个接口在后端去调用www.456.com/server.php并拿到返回值,然后再返回给index.html,这就是一个代理的模式。相当于绕过了浏览器端,自然就不存在跨域问题。
jquery插件无缝滚动实现原理:
1.很多时候使用方法Ul列表去展示。当然这也有一些好处,比如float对齐之类的。当然直接用p或者div也行。
2.了解overflow属性。在溢出情况下的处理。其实轮播就是在不断的处理li溢出的情况。
3 jQuery animate的动画效果。当然如果不用这个也行。一个setInterval就能搞定它。不过jQuery还是做了一些封装。
4 可能还需要一些基础的理解就是对定位的熟悉。margin和postion的了解。
5 之后就是循环轮播了,循环轮播需要对节点进行重新的修改。
具体而言就是在轮播到最后一张图片的时候,修改节点,将第一个节点,添加到列表的最后一个位置。如下:
- $(this).css({'margin-left':0}).children('li').last().after($(this).children('li').first());
看一下核心代码:
html:
- <div class="list" id = "sidle">
- <ul>
- <li><img src="1.jpg" width="538" height="198" /></li>
- <li><img src="2.jpg" width="538" height="198" /></li>
- <li><img src="3.jpg" width="538" height="198" /></li>
- <li><img src="4.jpg" width="538" height="198" /></li>
- </ul>
- </div>
css:
- .list{
- width:538px;
- height:198px;
- overflow:hidden;
- margin:50px auto;
- }
- .list ul{
- width:2152px;
- height:198px;
- 10. margin:0;
- 11. padding:0;
12. }
13. .list ul li{
- 14. float:left;
- 15. width:538px;
16. }
- (function($){
- var silde = {
- init:function(){
- this.auto();
- },
- auto:function(){
- var _root = this,
- $ul = $("#sidle").find("ul"),
- $lis = $ul.children("li"),
- 10. width = $lis.eq(0).width();
- 11. setInterval(function(){
- 12. $ul.animate({
- 13. 'margin-left':'-'+ width +'px'
- 14. },
- 15. 'slow',
- 16. function(){
- 17. //此处保证能循环轮播
- 18. //将已经轮播过的节点的第一张图片添加到末尾的位置
- 19. //再将margin-left重置为0px;
- 20. //这样就能一直的循环下去.
- 21. $ul.css({'margin-left':0}).
- 22. children('li').
- 23. last().
- 24. after(
- 25. $ul.children('li').first()
- 26. );
- 27. });
- 28. },2000
- 29. );
- 30. }
- 31. };
- 32. $(function(){silde.init();})
33. })(jQuery);
Vuex:
Vuex 是什么?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
什么是“状态管理模式”?
让我们从一个简单的 Vue 计数应用开始:
这个状态自管理应用包含以下几个部分:
- state,驱动应用的数据源;
- view,以声明方式将 state 映射到视图;
- actions,响应在 view 上的用户输入导致的状态变化。
以下是一个表示“单向数据流”理念的极简示意:
但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
另外,通过定义和隔离状态管理中的各种概念并强制遵守一定的规则,我们的代码将会变得更结构化且易维护。
这就是 Vuex 背后的基本思想,借鉴了 Flux、Redux、和 The Elm Architecture。与其他模式不同的是,Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
什么情况下我应该使用 Vuex?
在组件外部管理状态, 可以帮助我们管理共享状态
中小型单页应用,一个简单的 global event bus 就足够您所需了。
Axios:
axios 是一个基于 Promise 的,为浏览器和 Node.js 设计的 HTTP 客户端。它尽可能简化封装了 HTTP 相关的各种操作,在 Web App 中使用非常方便,官方建议使用 axios 进行 HTTP 操作
v-modle实现原理:
我们看上图中的代码,有行 $emit的代码,这行代码实际上会触发一个 input事件, 'input'后的参数就是传递给v-model绑定的属性的值,
也就是自定义的组件内部一般包含原生的表单组件(当然非表单的组件也可以)
然后,给原生控件绑定事件,捕捉到原生组件的值,利用 $emit方法,触发input方法,组件监听到 input事件然后把值传入到myattr中.
这里有个疑问,为什么是 'input'呢??? 三个字,看文档!
这个就是 vue对 v-model实现的一个规则: 使用了v-model的组件会
自动监听 input 事件,并把这个input事件所携带的值 传递给v-model所绑定的属性!这样组件内部的值就给到了父组件了
通过以上讲解,我们总结一下如何利用v-model实现自定义的表单组件:
监听原生组件的事件,当获取到原生组件的值后把值通过调用 $emit('input' ,data) 方法去触发 input事件
组件之间怎么通信:
1.父组件传递数据给子组件
父组件数据如何传递给子组件呢?可以通过props属性来实现
这样呢,就实现了父组件向子组件传递数据.
2.子组件与父组件通信
那么,如果子组件想要改变数据呢?这在vue中是不允许的,因为vue只允许单向数据传递,这时候我们可以通过触发事件来通知父组件改变数据,从而达到改变子组件数据的目的.
3.非父子组件通信
如果2个组件不是父子组件那么如何通信呢?这时可以通过eventHub来实现通信.
所谓eventHub就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件.
这样就实现了非父子组件之间的通信了.原理就是把Hub当作一个中转站!
你是如何搭建脚手架的:
一、环境搭建
- 安装node.js,从node.js官网下载并安装node,安装过程很简单,一路“下一步”就可以了(傻瓜式安装)。安装完成之后,打开命令行工具(win+r,然后输入cmd),输入 node -v,如下图,如果出现相应的版本号,则说明安装成功。
- 在硬盘上找一个文件夹放工程用的。这里有两种方式指定到相关目录:①cd 目录路径 ②如果以安装git的,在相关目录右键选择Git Bash Here
- 安装vue脚手架输入:vue init webpack exprice ,注意这里的“exprice” 是项目的名称可以说是随便的起名,但是需要主要的是“不能用中文”
2. 安装淘宝镜像,打开命令行工具,把这个(npm install -g cnpm --registry= https://registry.npm.taobao.org)安装完成之后输入 cnpm -v,如下图,如果出现相应的版本号,则说明安装成功。
3. 安装webpack,打开命令行工具输入:npm install webpack -g,安装完成之后输入 webpack -v,如下图,如果出现相应的版本号,则说明安装成功。
4. 安装vue-cli脚手架构建工具,打开命令行工具输入:npm install vue-cli -g,安装完成之后输入 vue -V(注意这里是大写的“V”),如下图,如果出现相应的版本号,则说明安装成功。
一. 用vue-cli来构建项目
- cd 命令进入创建的工程目录,首先cd exprice(这里是自己建工程的名字);
- 安装项目依赖:npm install,因为自动构建过程中已存在package.json文件,所以这里直接安装依赖就行。不要从国内镜像cnpm安装(会导致后面缺了很多依赖库),但是但是如果真的安装“个把”小时也没成功那就用:cnpm install 吧
- 安装 vue 路由模块 vue-router 和网络请求模块 vue-resource,输入:cnpm install vue-router vue-resource –save
创建完成的“exprice”目录如下:
数面试:
css部分
- position有哪些属性?
- 盒模型中的content如何固定100px?
设置 box-sizing: content-box;
- transition/translate/transform 如何实现2s使一个with100px的盒子变成200px?
transition过渡属性
transition-property
transition-duration
transition-timing-function: linear/ease
transition-delay
- 容器中的不定长宽div如何上下左右居中对齐?
js部分
- 原生js如何获取时间戳?
Date.parse(new Date())
(new Date()).valueOf()
new Date().getTime()
- JSON两个转换方法记得吗?
JSON.parse()
JSON.stringify()
- 如何用jquery实现列表奇偶行设置自定义颜色?
//偶数行:even
$(“ul li:even”).css(‘backgroundColor’: ‘blue’)
//偶数行:odd
$(“ul li:odd”).css(‘backgroundColor’: ‘green’)
- 普通数组与对象数组如何快速排序?数组遍历方法有哪些?map方法参数有哪些,有什么作用?
普通数组:常用方法sort()为数组排序,默认会调用toString()方法比较ASCII值升序排序。
对象数组:编写一个函数参数为(arr, prop, desc)
- 要利用数组sort方法就先初始化一个空数组
- 数组长度做全局缓存
- 比较属性prop的键值数据类型都需要做判断
- 最后调用数组的sort方法
- 最后是数组拷贝到目标数组
- 返回该目标数组
- 对象排序怎么做?
- 获取对象属性集合Object.keys()
- Object.keys = Object.keys || function(obj){
var a = [];
//简洁巧妙,遍历同时赋值
for(a[a.length] in obj){
return a;
}
}
注意旧版本的IE,不支持for in遍历名为valueOf和toString的属性名
- 遍历数组和对象分别有哪些方法?效率高的是什么方法?
1.1 for-in遍历数组或者对象,i值代表数组每一项的下标值,或者代表对象的每一项的key值。(特别为遍历对象设计)
1.2 forEach遍历数组,三个参数依次是数组元素、索引、数组本身(只能遍历数组) arr.forEach(value, index, arr)
1.3 能遍历对象和数组—通用的forEach方法
function forEach(obj){
var key;
If( obj instantceof Array ){
obj.forEach(function(item){
console.log(item);
})
}else{
for(var key in obj){
console.log(key, obj[key]);
}
}
}
//for-of遍历Map对象, 遍历字符串”china中国”
let iterable = new Map([[“a”: 1],[“b”: 2],[“c”: 3]]);
for(let [key, value] in iterable){
console.log(value);
}
$.each(function(index, value){})遍历对象和数组
_.each(arrTmp,function(value,index,array){}遍历对象和数组
- javascript原生遍历方法的建议用法:
用for循环遍历数组
用for-in遍历对象
用for-of遍历类数组对象(ES6)
用Object.keys()获取对象属性名的集合
- 数组对象嵌套的情况怎么排序?
- 如何复制一个数组或者一个对象?有更快速便捷的方式吗?
复制有浅拷贝与深拷贝之分:
1.1 浅拷贝是赋值操作,只是创建了一份原内容的引用
1.2 深拷贝有三种方法
1.2.1 遍历复制
1.2.2 (最快的复制方法1是concat一个空数组)
arrayObject.concat(arrayX, arrayX…)
(最快的复制方法2是slice(start, end)从头截到尾)
arr.slice(0)
都不改变原数组且返回被连接数组的一份拷贝
1.3 实例:
var objDeepCopy = function(source){
var sourceCopy = source instanceof Array ? [] : {};
for(var item in source){
sourceCopy[item] = typeof source[item] === 'object' ? objDeepCopy(source[item]) : source[item];
}
return sourceCopy;
}
- (5,10)之间的随机数怎么获取?
Math.random() * (max - min) + min
Math.floor(Math.random()*(max-min)+min)
Math.round((Math.random()*(max-min)+min)*10)/10
- typeof [] 输出值是什么?
typeof 有哪些返回值类型:
10.1 boolean (true false)
10.1 number (NaN Infinity)
10.2 string ("123")
10.3 function (Date eval)
10.4 object (window document null [] {})
10.5 undefined (undefined sass)
- Js如何判断值是否为数字?
1.1 使用isNaN()函数处理,会把””/[]/null当作0处理,视为数字
··· 11.2 function isNaN(val){
If(val === “” || val == null || val == []){
return false;
} else if(!isNaN(val)){
return true;
}else{
return false;
}
}
- 两个数组如何连接在一起?数组与字符串直接转换方法是什么?
concat()方法和slice(start,end)截取返回都不改变原数组:快速深拷贝一个数组
数组转字符串: join(“”)
字符串转数组:split(“,”)
项目部分
- 你在项目中用过哪些技术?
- 负责哪些模块的实现?
- 项目中碰到过什么问题?
- 你是怎么解决的?
电话面试:
flex 应用
栅格布局
前端缓存技术有用过哪些
什么是原型链?有哪几种方法实现继承,多态,封装?
闭包是什么?用闭包实现过什么功能?
Js事件都有哪些?
vue的mvvm实现原理
vue路由实现原理
vue的钩子函数有哪些?
vue的:和 @分别代表什么含义?
vue项目的开发目录还记得吗?有公司公用的组件怎么放置的?
前后端分离 打包发布怎么做的
面试笔试题:
解析url:http://www.qq.com?tag=12 p 5ih&g=&u=50为json对象
(Window.foo||(window.foo=”bar”)) window.foo的值是什么?
描述下position的relative和absolute的原理和关系?
Css如何清除浮动?
编写一个高效的数组去重方法
请简述Onload和DomContentLoad的区别?
一个类的方法写在构造函数里边与写在原型中的区别?
简述下创建Ajax|请求的过程,描述下什么是跨域?
Vue中v-bind 和 v-on的分别是什么?
Js的基本数据类型有哪些?
Get和Post有什么区别?
描述Expires和 Cache-control的功能细节?
简述xss的原理,如何预防?
Repaint和reflow是什么?