前端面试所遇到的技术点:
面试问题:
HTML:
常见的HTML标签:
(1)行标签和块级标签分别有哪些?
(2)常见的HTML5的标签有哪些?
(3)如何减少HTTP的请求和优化?
减少请求的资源方法:
将多个css资源文件打包到一个文件里。将多个js打包到一个js文件里。针对图片资源:可采用雪碧图将多个图片放置到一个图片里。
尽量的压缩css文件,js文件,图片文件,采用无损压缩的方式或者是使用webP格式的图片。
(4)html5和HTML4的区别
html5可以自定义标签,并兼容html4,比html4多出了一些标签,canvas/video/audio/iframe等等,多出些js相关API
css:
(1)选择器问题,
id高于class,越详细越精确的选择器权重越高,!important可迅速提高权重
(2)布局相关问题
正常布局,圣杯布局(上面一大块中间三小块下边一大块)、居中定位、REM布局的原理、弹性布局、清除浮动问题( clear:both
)
(3)transform位移(translate),旋转(rotate)、倾斜(skew)、缩放(scale)问题?
(4)动画、过度性能优化的问题?
尽量减少非常多元素同时产生动画,尽量少的在1个元素里设置多个动画效果,位移的话尽量使用transform的translate来做位移,不要用定位left、top、right、bottom来实现位移。
js:
(1)变量的提升:
引擎将变量声明提升到了函数顶部、
函数的提升:
为什么函数可以在声明之前就可以调用,并且跟变量声明不同的是,它还能得到正确的结果,其实引擎是把函数声明整个地提升到了当前作用域的顶部,函数的优先权是最高的,它永远被提升至作用域最顶部,然后才是函数表达式和变量按顺序执行
(详见:https://www.cnblogs.com/liuhe688/p/5891273.html)
(2)构造对象,构造对象的方法
构造函数、class、工程模式构造对象、单列模式
:原型模式
function
Person(){
}
Person.prototype.name =
"bill"
;
Person.prototype.address =
"GuangZhou"
;
Person.sayName =
function
(){
alert(
this
.name);
}
var
person1 =
new
Person();
var
person2 =
new
Person();
//测试代码
alert(person1.name);
// bill
alert(person2.name);
// bill
person1.sayName();
//bill
person2.sayName();
//bill
person1.name =
"666"
;
alert(person1.name);
// 666
alert(person2.name);
// bill
person1.sayName();
//666
person2.sayName();
//bill
构造函数模式
function Person(name, url) { //注意构造函数名第一个字母大写
this.name = name;
this.url = url;
this.alertUrl = alertUrl;
}
function alertUrl() {
alert(this.url);
}
工厂模式
function
a(name){
var
b =
new
object();
b.name = name;
b.say =
function
(){
alert(
this
.name);
}
return
b
}
(3)什么是原型链、原型对象、怎么在原型链上添加方法,如何通过原型实现继承?
在prototype里添加方法,实例化出来的对象_protp_
(4)this的指向问题
this是根据函数被哪个对象调用,那么这个this就指向谁,要不然就指向globle或者window,在箭头函数里,箭头函数定义的时候,this指向谁就一直指向谁,
改变this的指向:通过call/apply/bind都可以改变this的指向。
(5)数组常见的方法和排序
数组的增删改查、数组排序、数组的复制:
- ary.splice(n,m,x)从索引n开始删除m个元素,把新增的元素X放在索引n的前面,把删除的元素当成一个新数组返回,原有数组改变
- ary.pop() 删除数组的最后一项,返回的是删除的那一项,原有数组改变
- ary.shift() 删除数组的的第一项,返回的是删除的那一项,原有数组改变
- ary.push()
- 向数组末尾添加元素,返回的是添加后新数组的长度,原有数组改变
- ary.unshift()
- 向数组开头添加元素,返回的是添加后新数组的长度,原有数组改
- slice(n-1,m)把数组的第n项到第m项提取出来
- slice(n) 从索引n开始查找到数组末尾
- slice(0) slice() 将原有数组复制一份 属于数组克隆
- concat() 也可以实现数组克隆
- concat的本意是实现数组的拼接 ary.concat(ary2) 把两个数组进行拼接
- reverse() 把数组倒过来排序,原有数组改变
- sort 可以实现由大到小或者由小到大的排序
- indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
- foreach
- map
(6)事件问题
。。Onclick和addEventListener这两种方式监听事件的区别:
addEventListener:一个事件可以绑定多个函数,很多新出的移动端事件比如touch等只有他支持,还可以设置捕获或者冒泡进行监听
。。如何阻止冒泡?
Event.cancelbubble=true
。。事件传参问题?
一般在元素上绑定data-xx=‘xx‘
(7)如何处理操作dom 对元素对象的增删改查:
1. 增
创建元素节点 :document.createElement(“div”);
创建text节点 :document.createTextNodet(“内容”);
复制一个节点: var newNode = node.cloneNode();//参数为true复制所有子节点,参数为false只执行一次浅复制。
2. 删
removeChild();//该方法不是在待删除的节点上调用,而是在它的父元素节点上调用。
node.parentElement.removeChild(node);
replaceChild();//删除一个子节点,并用一个新的节点取代它。第一个参数是新节点,第二个参数是要删除的节点。
node.parentElement.replaceChild(newNode,node);
获取和设置非标准的HTML属性
Element定义了getAttribute和setAttribute方法来查询和设置非标准属性,hasAttribute和removeAttribute来检测命名属性是否存在和完全删除属性。
对内容的修改
innerHTML:包含标签的内容
innerText(火狐支持不好):纯文本的元素内容
textContent(IE不支持):纯文本的元素内容
4. 查
一步查找到位
document.getElementById() 返回对拥有指定 id 的第一个对象的引用。
document. getElementsByClassName() 返回文档中所有指定类名的元素集合。
document.getElementsByName() 返回带有指定名称的对象集合。
document.getElementsByTagName() 返回带有指定标签名的对象集合。
查找父子兄弟
对于一个Node节点,包含很多种,像:Document节点、Text节点、Comment节点、Element节点,我们常常需要获得的是元素节点,忽略掉Text和Comment节点:
firstElementChild,lastElementChild;
children => 数组类型:children[0] ,第一个子节点
nextElementSibling,previousElementSibling => 兄弟节点
parentElement => 父亲节点
5. 插
Node有方法appendChild()和insertBefore()。
parent.appendChild(child); // 插入到最后
parent.insertBefore(newNode,node);//插入到node之前
(8)如何获取元素的一些信息:元素的大小、屏幕的宽度、元素的位置
获取元素的位置和尺寸:https://www.cnblogs.com/cloud-k/p/7681386.html
4、元素的大小及其相对于视口的位置
getBoundingClientRect()
5、上边偏移量,左边的偏移量
offsetTop
offsetLest
6、可视区域的大小
document.documentElement.clientWidth
document.documentElement.clientHeight
7、页面的实际大小
document.documentElement.scrollWidth
document.documentElement.scrollHeight
10、屏幕可用宽高(去除任务栏)
window.screen.availWidth
window.screen.availHeight
11、窗口的内高度、内宽度(文档显示区域+滚动条)
window.innerWidth
window.innerHeight
12、窗口的外高度、外宽度
window.outerWidth
window.outerHeiht
(9)如何获取浏览器的一些信息:url地址获取、userAgent的获取,地理位置的获取
获取浏览器信息需要使用navigator.userAgent 对象 根据获取到的内容判断浏览器信息
Navigator 对象包含有关浏览器的信息。js就是通过Navigator的属性获取客户端浏览器信息
Navigator 对象属性:
appCodeName 返回浏览器的代码名。
appMinorVersion 返回浏览器的次级版本。
appName 返回浏览器的名称。
appVersion 返回浏览器的平台和版本信息。
browserLanguage 返回当前浏览器的语言。
cookieEnabled 返回指明浏览器中是否启用 cookie 的布尔值。
cpuClass 返回浏览器系统的 CPU 等级。
onLine 返回指明系统是否处于脱机模式的布尔值。
platform 返回运行浏览器的操作系统平台。
systemLanguage 返回 OS 使用的默认语言。
userAgent 返回由客户机发送服务器的 user-agent 头部的值。
userLanguage 返回 OS 的自然语言设置。
在WEB开发中,时常会用到javascript来获取当前页面的url网址信息
1、window.location.href(设置或获取整个 URL 为字符串)
var test = window.location.href;
alert(test);
返回:http://i.cnblogs.com/EditPosts.aspx?opt=1
2、window.location.protocol(设置或获取 URL 的协议部分)
var test = window.location.protocol;
alert(test);
返回:http:
3、window.location.host(设置或获取 URL 的主机部分)
var test = window.location.host;
alert(test);
返回:i.cnblogs.com
4、window.location.port(设置或获取与 URL 关联的端口号码)
var test = window.location.port;
alert(test);
返回:空字符(如果采用默认的80端口(update:即使添加了:80),那么返回值并不是默认的80而是空字符)
5、window.location.pathname(设置或获取与 URL 的路径部分(就是文件地址))
var test = window.location.pathname;
alert(test);
返回:/EditPosts.aspx
6、window.location.search(设置或获取 href 属性中跟在问号后面的部分)
var test = window.location.search;
alert(test);
返回:?opt=1
PS:获得查询(参数)部分,除了给动态语言赋值以外,我们同样可以给静态页面,并使用javascript来获得相信应的参数值。
7、window.location.hash(设置或获取 href 属性中在井号“#”后面的分段)
var test = window.location.hash;
alert(test);
返回:空字符(因为url中没有)
8、js获取url中的参数值???逻辑判断下来琢磨
用户地理位置的 获取:
获取用户地理位置关键api:
navigator.geolocation.getCurrentPosition(showPosition,showError,option)
其中三个参数分别表示:
showPosition : 必选,执行成功的回调
showError : 可选,执行错误的回调
option: 可选,设置数据获取的方式
showPosition属性
coords.accuracy : 获取位置的精度
coords.altitude : 获取海拔(米)
coords.altitudeAccuracy : 获取位置的海拔精度
coords.heading : 获取方向
coords.latitude : 获取纬度
coords.longitude : 获取经度
coords.speed : 获取速度
timestamp : 获取相应的时间
showError 属性
PERMISSION_DENIED : 用户拒绝页面发起的地理位置
POSITION_UNAVAILAVLE : 无法获取当前位置
TIMEOUT : 超时
option 参数
enableHighAcuracy : 是否启动高精模式(布尔值)
maximumAge : 设置定位缓存过期的时间(毫秒,0为禁用缓存)
timeout : 设置获取定位信息的时常 (超时触发ErrorCallback)
具体示例:
var option = {
enableHighAccuracy:true, //设置提升定位的精准度
maximumAge:0, //禁用缓存
timeout:30000 //开始获取定位信息30秒后超时
}
if(navigator.geolocation){ //判断是否支持Geolocation API
navigator.geolocation.getCurrentPosition(showPosition,showError,option)
}
function showPosition(position){
var lat = position.coords.latitude; //获取纬度
var lon = position.coords.longitude; //获取经度
alert("您的纬度是:"+lat+ ",经度是:"+lon);
}
function showError(error){
switch(error.code){
case error.PERMISSION_DENIED:
alert("您拒绝了地理定位服务");
break;
case error.POSITION_UNAVAILABLE:
alert("无法获取您的位置");
break;
case error.TIMEOUT:
alert("超时");
break;
}
}
(10)jQuery的链式原理、
DOM链式调用的处理:
1.节约JS代码.
2.所返回的都是同一个对象,可以提高代码的效率。
//定义一个JS类
function Demo() {
}
//扩展它的prototype
Demo.prototype ={
setName:function (name) {
this.name=name;
console.log(this)
return this;
},
getName:function (name) {
// return this.name;
this.sex=name
console.log(this)
return this
},
setAge:function (age) {
this.age=age;
console.log(this)
return this;
}
};
////工厂函数
function D() {
return new Demo();
}
//去实现可链式的调用
D().setName("CJ").setAge(18).setName();
(11)jQuery常用的方法有哪些?
效果:
$("p").show() //显示隐藏的匹配元素 $("p").show("slow"); //参数表示速度,("slow","normal","fast"),也可为900毫秒 $("p").hide() //隐藏显示的元素 $("p").toggle(); //切换 显示/隐藏
页面载入
当页面载入成功后再运行的函数事件
$(document).ready(function(){
do something...
});
//简写
$(function($) {
do something...
});
详细介绍见:https://www.cnblogs.com/LeoBoy/p/5849079.html
或者:http://www.php.cn/js-tutorial-378860.html
vue框架:
(12)vue虚拟dom是什么原理?
虚拟DOM来提升页面的刷新速度:
Virual DOM是用JS对象记录一个dom节点的副本,当dom发生更改时候,先用
虚拟dom进行diff,算出最小差异,然后再修改真实dom。
vue的virtual dom的diff算法是基于snabbdom算法改造而来,与react的diff算法一样
仅在同级的vnode间做diff,递归的进行同级vnode的diff,最终实现整个DOM树的更新。
虚拟DOM的缺点:
1. 代码更多,体积更大
2. 内存占用增大
3. 小量的单一的dom修改使用虚拟dom成本反而更高,不如直接修改真实dom快,所以一般简单的页面制作可以直接用jQuery,而不用框架
(13)vue数据双向绑定原理?
首先我们为每个vue属性用Object.defineProperty()实现数据劫持,为每个属性分配一个订阅者集合的管理数组dep;然后在编译的时候在该属性的数组dep中添加订阅者,v-model会添加一个订阅者,{{}}也会,v-bind也会,只要用到该属性的指令理论上都会,接着为input会添加监听事件,修改值就会为该属性赋值,触发该属性的set方法,在set方法内通知订阅者数组dep,订阅者数组循环调用各订阅者的update方法更新视图。
详见:https://www.cnblogs.com/zhenfei-jiang/p/7542900.html
(14)vue路由原理?
详见:https://segmentfault.com/a/1190000014822765
更新视图但不重新请求页面,是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有2
种方式:
- 利用
URL
中的hash
("#"
); - 利用
History interface
在HTML5
中新增的方法;
- 每一次改变
hash
(window.location.hash
),都会在浏览器访问历史中增加一个记录。
利用hash
的以上特点,就可以来实现前端路由"更新视图但不重新请求页面"的功能了。
HashHistory
hash
("#"
)符号的本来作用是加在URL
指示网页中的位置:
http://www.example.com/index.html#print
#
本身以及它后面的字符称之为hash
可通过window.location.hash
属性读取.
hash
虽然出现在url
中,但不会被包括在http
请求中,它是用来指导浏览器动作的,对服务器端完全无用,因此,改变hash
不会重新加载页面。- 可以为
hash
的改变添加监听事件:
window.addEventListener("hashchange",funcRef,false)
- 每一次改变
hash
(window.location.hash
),都会在浏览器访问历史中增加一个记录。
利用hash
的以上特点,就可以来实现前端路由"更新视图但不重新请求页面"的功能了。
transitionTo()
方法是父类中定义的是用来处理路由变化中的基础逻辑的,push()
方法最主要的是对window
的hash
进行了直接赋值:window.location.hash=route.fullPath
HashHistory.replace():
replace()方法与push()方法不同之处在于,它并不是将新路由添加到浏览器访问历史栈顶,而是替换掉当前的路由:
HTML5History
History interface
是浏览器历史记录栈提供的接口,通过back()
,forward()
,go()
等方法,我们可以读取浏览器历史记录栈的信息,进行各种跳转操作。
从HTML5
开始,History interface
提供了2个新的方法:pushState()
,replaceState()
使得我们可以对浏览器历史记录栈进行修改:
window.history.pushState(stateObject,title,url)
window.history,replaceState(stateObject,title,url)
stateObject
:当浏览器跳转到新的状态时,将触发popState
事件,该事件将携带这个stateObject
参数的副本title
:所添加记录的标题url
:所添加记录的url
这2
个方法有个共同的特点:当调用他们修改浏览器历史栈后,虽然当前url
改变了,但浏览器不会立即发送请求该url
,这就为单页应用前端路由,更新视图但不重新请求页面提供了基础。
一般的需求场景中,hash
模式与history
模式是差不多的,根据MDN
的介绍,调用history.pushState()
相比于直接修改hash
主要有以下优势:
pushState
设置的新url
可以是与当前url
同源的任意url
,而hash
只可修改#
后面的部分,故只可设置与当前同文档的url
pushState
设置的新url
可以与当前url
一模一样,这样也会把记录添加到栈中,而hash
设置的新值必须与原来不一样才会触发记录添加到栈中pushState
通过stateObject
可以添加任意类型的数据记录中,而hash
只可添加短字符串pushState
可额外设置title
属性供后续使用
(15)vuex状态管理的整个过程是什么样的?
理解什么是状态管理模式?
状态管理:简单的理解就是统一管理和维护各个vue组件的可变化状态。
我们明白vue是单向数据流的,那么它的状态管理一般包含如下几部分:
1. state; 驱动应用的数据(一般指data中返回的数据)。
2. view; 一般指模板,以声明的方式将state的数据映射到视图。
3. actions: 响应在view上的用户输入导致的状态变化。
但是当我们的应用遇到多个组件共享状态时候,那么单向数据流可能不太满足我们的需求:
比如如下几个方面:
1. 多个视图依赖于同一状态。
传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。
2. 我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
因此我们可以把组件的共享状态提取出来,作为全局来管理,因此vuex产生了。
vuex的优点:
最主要解决了组件之间共享同一状态的问题。可以把组件的共享状态提取出来,作为全局来管理。
什么情况下我应该使用 Vuex?
如果不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,最好不要使用 Vuex。一个简单的 global event bus 就足够您所需了。但是,如果您需要构建是一个中大型单页应用,很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
二: Vuex状态管理的demo学习
每一个Vuex应用的核心就是store(仓库), store是保存应用中大部分的状态。
Vuex 和一般的全局对象有以下几点不同:
1. Vuex的状态存储是响应性的。
当vue组件从store中读取状态的时候,若store中的状态发生变化,那么相对应的组件也就会得到相应的更新。
2. 我们不能直接修改store中的状态。
改变store中的状态的唯一途径是显示地提交(commit)mutations.
2-1 单一状态树
Vuex使用的是单一状态树,用一个对象就包含了全部的应用层级状态。这也意味着每个应用将仅仅包含一个store的实列。
Vuex的状态存储是响应性的,因此从store实列中读取一个状态的最简单的方法是在计算属性返回某个状态。
注意:state是用来存储初始化的数据的。如果要读取数据使用
store.state.数据变量。修改数据使用mutations,它保存的需要改变数据的所有方法,改变mutations里的数据需要使用store.state.数据变量。
修改数据使用mutations,它保存的需要改变数据的所有方法,改变mutations里的数据需要使用store.commit();
详见:https://www.cnblogs.com/tugenhua0707/p/8098496.html
(16)vue生命周期的过程?
(17)
react框架:
(18)react虚拟dom是什么原理?
(19)react路由原理?
(20)redux是什么原理的?
(21)redux生命周期的过程?
(22)小程序的一些常见的API方法
-
? 本地缓存
-
通过key的形式添加缓存setStorage (异步接口)
wx.setStorage({
key:"key"
data:"value"
})
-
通过key的形式获取缓存getStorage (异步接口)
wx.getStorage({
key: ‘key‘,
success: function(res) {
console.log(res.data) }
})
-
从本地缓存中异步移除指定 key
wx.removeStorage({
key: ‘key‘,
success: function(res) {
console.log(res.data)
}
})
-
清理本地数据缓存
wx.clearStorage()
? 获取用户信息,需要先调用wx.login 接口
wx.getUserInfo({
success: function(res) {
var userInfo = res.userInfo
var nickName = userInfo.nickName
var avatarUrl = userInfo.avatarUrl
var gender = userInfo.gender //性别 0:未知、1:男、2:女
var province = userInfo.province
var city = userInfo.city
var country = userInfo.country
}
})
-
拨打电话
wx.makePhoneCall({
phoneNumber: ‘1340000‘ //仅为示例,并非真实的电话号码
}
详见:https://www.cnblogs.com/lovebing/p/8794538.html
原文地址:https://www.cnblogs.com/Dark-fire-liehuo/p/9615081.html