前端面试锦囊1

css篇

px、rem、em的区别?
1、rem 和 em 单位是由浏览器基于你的设计中的字体大小计算得到的像素值,适用于响应式布局。
2、em 单位基于使用他们的元素的字体大小。
3、rem 单位基于 html 元素的字体大小。
4、em 单位可能受任何继承的父元素字体大小影响
5、rem 单位可以从浏览器字体设置中继承字体大小。
6、使用 em 单位应根据组件的字体大小而不是根元素的字体大小。
7、在不需要使用em单位,并且需要根据浏览器的字体大小设置缩放的情况下使用rem。
8、使用rem单位,除非你确定你需要 em 单位,包括对字体大小。
9、媒体查询中使用 rem 单位
10、不要在多列布局中使用 em 或 rem -改用 %。
11、不要使用 em 或 rem,如果缩放会不可避免地导致要打破布局元素。
12、px是固定的像素,一旦设置就无法因为适应页面大小而改变
CSS选择器有哪些?哪些属性可以继承?CSS优先级算法如何计算?
CSS选择符:id选择器(#myid)、类选择器(.myclassname)、标签选择器(div, h1, p)、相邻选择器(h1 + p)、子选择器(ul > li)、后代选择器(li a)、通配符选择器(*)、属性选择器(a[rel=”external”])、伪类选择器(a:hover, li:nth-child)
可继承的属性:font-size, font-family, color
不可继承的样式:border, padding, margin, width, height
优先级(就近原则):!important > [ id > class > tag ]
!important 比内联优先级高
CSS有哪些定位方式?他们分别有什么特点?
定位方式:相对定位、绝对定位、固定定位
relative 相对定位,相对定位不脱离文档流,参考其在原来文档流中的位置,通过 top,bottom,left,right 定位,并 且可以通过z-index进行层次分级。
• absolute 绝对定位,绝对定位脱离文档流,依据最近的已经定位(绝对、相对或固定定位)的父元素,通过 top,bottom,left,right 定位。当父级 position 为 static 时,absolute元素将依据body根元素(浏览器窗口)进行定 位,可以通过z-index进行层次分级。
• fixed 固定定位,固定定位与父元素无关(无论父元素是否定位),直接根据浏览器窗口定位,且不随滚动条拖动 页面而滚动,可通过z-index进行层次分级。
描述下盒子模型,他们有什么区别,使用什么属性去改变盒子模型?
标准盒子模型(content-box):宽度=内容的宽度(content)+border+padding+margin
IE盒子模型(border-box):宽度=内容宽度(content+border+padding)+margin
说出水平垂直居中方法(至少两种)

<div class=”box”></div>
.box{width:200px;height:400px;position:absolute;left:50%;top:50%;margin-left:-100px;margin-top:-200px;}
.box{width:200px;height:400px;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%;}
.box{width:200px;height:400px;position:absolute;left:0;top:0;right:0;bottom:0;margin:auto;}

页面布局方式(至少3种)
流体布局、圣杯布局、双飞翼布局、flex布局
请解释一下 CSS3 的 flexbox(弹性盒布局模型),以及适用场景?
该布局模型的目的是提供一种更加高效的方式来对容器中的条目进行布局、对齐和分配空间。在传统的布局方式中,block 布局是把块在垂直方向从上到下依次排列的;而 inline 布局则是在水平方向来排列。弹性盒布局并没有这样内在的方向限制,可以由开发人员自由操作。
试用场景:弹性布局适合于移动前端开发,在Android和ios上也完美支持。
为什么要初始化 CSS 样式?
因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对CSS初始化往往会出现浏览器之间的页面显示差异。
CSS有哪些伪类样式?
p:first-of-type 选择属于其父元素的首个元素
p:last-of-type 选择属于其父元素的最后元素
p:only-of-type 选择属于其父元素唯一的元素
p:only-child 选择属于其父元素的唯一子元素
p:nth-child(2) 选择属于其父元素的第二个子元素
:enabled :disabled 表单控件的禁用状态。
:checked 单选框或复选框被选中。
列举HTML5新特性(至少5种)?
1、拖拽释放(Drap and drop) API ondrop
2、自定义属性data-id
3、语义化更好的内容标签(header,nav,footer ,aside, article, section)
4、地理(Geolocation) API
5、表单控件 calendar , date , time , email , url , search , tel , file , number
6、新的技术 webworker, websocket , Geolocation
列举Css3新特性
媒体查询、盒阴影、边框图片、字体属性、圆角边框、文字阴影、自定义动画、过渡、渐变
行级、块级元素有哪些,他们有什么区别?
行级:a span b em i input image select
块级:div h1~h6 ul li dd dt dl p table
区别:1. 块级元素会独占一行,其宽度自动填满其父元素宽度
行内元素不会独占一行,相邻的行内元素会排列到同一行里,直到一行排不下,才会换行,其宽度随元素的内容变化而变化,
2. 一般情况下,块级元素可以设置width,height属性,行内元素设置width,height无效(注意,块级元素设置了width宽度属性后仍然是独占一行的)
3. 块级元素可以设置margin,padding属性
行内元素的水平方向的padding-left和padding-right都会产生边距效果,但是竖直方向上的padding-top和padding-bottom都不会产生边距效果

隐藏元素的方式有哪些?
Display:none;overflow:hidden; visibility:hidden;
display:none 不显示对应的元素,在文档布局中不再分配空间(回流+重绘)
visibility:hidden 隐藏对应元素,在文档布局中仍保留原来的空间(重绘)

JS篇

JS的数据类型有哪些?
Undefined、null、boolean、number、string
常用的数组方法有哪些?
1.push()向数组的末尾添加新内容,返回新增后的数组长度,改变原数组
2.Pop()删除数组最后一项,返回被删除的项,改变原数组
3.Shift()删除数组的第一项,返回被删除的项,改变原数组
4.Unshift()向数组首位添加新的内容,返回新数组的长度,改变原数组
5.Slice()按条件查找出其中的部分内容,返回新数组,不改变原数组
array.slice(n, m),从索引n开始查找到m处(不包含m)
array.slice(n) 第二个参数省略,则一直查找到末尾
array.slice(0)原样输出内容,可以实现数组克隆
array.slice(-n,-m) slice支持负参数,从最后一项开始算起,-1为最后一项,-2为倒数第二项
6.Splice():对数组进行增删改,返回删除的新数组,原有数组改变
增加:ary.splice(n,0,m)从索引n开始删除0项,把m或者更多的内容插入到索引n的前面
返回空数组
修改:ary.splice(n,x,m)从索引n开始删除x个,m替换删除的部分
把原有内容删除掉,然后用新内容替换掉
删除:ary.splice(n,m) 从索引n开始删除m个内容
(如果第二个参数省略,则从n删除到末尾)
7.Join()用指定的分隔符将数组每一项拼接为字符串,返回拼接好的字符串,不改变原数组
8.Concat()用于连接两个或多个数组,返回连接后的新数组,不改变原数组
9.IndexOf()检测当前值在数组中第一次出现的位置索引,第一次查到的索引,未找到返回-1,不改变原数组
array.indexOf(item,start) item:查找的元素 start:字符串中开始检索的位置
10.forEach()循环遍历数组每一项,forEach中不能使用continue和break,forEach中不能跳出,只能跳过(return跳过)
函数 ary.forEach(function(item,index,ary){}) item:每一项 index:索引 ary:当前数组
常用的字符串方法有哪些?
1.charAt(index)通过index索引值查到对应的字符串
2.charCodeAt(index)是通过索引找到当前索引字符的ASCll码,如果没有,则返回NaN
3.indexOf(寻找的字符,【开始寻找的位置】)如果找到则返回当前字符的索引,找不到则返回 -1.第二个参数表示从那个索引位置开始 查找,如果是负数,说明从后往前数的第几位,(但是绝对值大于整个字符串的长度,则位置从头开始)
4.substring(indexStart,indexEnd)返回的是indexStart 开始到indexEnd结束的一个字符串,该字符串是原字符串的子集,包括开始位置,不包括结束位置
5.slice(beginIndex,endIndex)是beginIndex开始到endIndex结束的一个字符串,该字符串是原字符串的子集,包括开始位置,不包括结束位置
6.substr(start,length)返回一个字符串中从指定位置开始到指定字符数的字符。从start开始,截取length个
7.split()用来指定分隔符将字符串分割成一个字符串数组的方法,可以指定分割的字符,如果是个’ ',空字符串,默认和数组一样的格式,就是逗隔开
8.replace()返回由替换值替换部分或者所有的之后的新字符串,被替换的可以是个字符串,也可以是个正则表达式。替换值可以是一个或者多个字符串,如果选择被替换的是个字符串,则仅替换第一个匹配项
9.repeat(数字)构造并返回一个新字符串,该字符串包含被连接在一起的指定数量的字符串的副本。里面的数字必须为正数,如果是小数,则默认取整
常用的对象方法有哪些?
1.hasOwnProperty():返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)
2.isPrototypeOf():用于测试一个对象是否存在于另一个对象的原型链上
3.toString():返回一个表示该对象的字符串
4.valueOf():返回指定对象的原始值
5.Object.assign():用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象
6.Object.create():创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。即创建一个以指定的对象为原型的子对象
7.Object.setPrototypeOf():设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或null
8.Object.getPrototypeOf():返回指定对象的原型(内部[[Prototype]]属性的值)
9.Object.defineProperties():直接在一个对象上定义新的属性或修改现有属性,并返回该对象
10.Object.defineProperty():会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象
11.Object.keys():会返回一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用for…in循环遍历该对象时返回的顺序一致 。
12.Object.values():返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for…in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )
13.Object.entries():返回一个给定对象自身可枚举属性的键值对数组,其排列与使用for…in循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)
14.Object.fromEntries():把键值对列表转换为一个对象,是Object.entries()的逆操作。
15.Object.is():判断两个值是否是相同的值
数组遍历方法有哪些?
1.forEach:遍历数组

var arr=[1,2,3,4,5]
for(var i=0;i<arr.length;i++){
console.log(arr[i])//1,2,3,4,5
}
arr.forEach(function(value,index){
console.log(value)//1,2,3,4,5
})

2.map:将数组映射成另一个数组,通过指定函数处理数组的每一个元素,并返回处理后的新数组

 var numbers = [1,2,3];
var doubledNumbers = [];
// es5写法
 for(var i = 0; i < numbers.length; i++){
 doubledNumbers.push(numbers[i] * 2);
 }
 console.log(doubledNumbers);//[2,4,6]

// es6 map方法
 var doubled = numbers.map(function(number){
   return number * 2;
 })
 console.log(doubled);//[2,4,6]

3.filter:从数组中找出所有符合指定条件的元素

//1.假定有一个对象数组(A),获取数组中指定类型的对象放到B数组中
var porducts = [
  {name:"cucumber",type:"vegetable"},
  {name:"banana",type:"fruit"},
  {name:"celery",type:"vegetable"},
  {name:"orange",type:"fruit"}
];
// es5写法
var filteredProducts = [];
for(var i = 0; i < porducts.length; i++){
    if(porducts[i].type === "vegetable"){
      filteredProducts.push(porducts[i]);
    }
}
console.log(filteredProducts);//[{name: "cucumber", type: "vegetable"},
                                 {name: "celery", type: "vegetable"}]
 // es6 filter
 var filtered2 = porducts.filter(function(product){
 return product.type === "vegetable";
})
console.log(filtered2);
//2假定有一个对象数组(A),过滤掉不满足以下条件的对象
//条件: 蔬菜 数量大于0,价格小于10
var products = [
  {name:"cucumber",type:"vegetable",quantity:0,price:1},
  {name:"banana",type:"fruit",quantity:10,price:16},
  {name:"celery",type:"vegetable",quantity:30,price:8},
  {name:"orange",type:"fruit",quantity:3,price:6}
];
products = products.filter(function(product){
    return product.type === "vegetable"
    && product.quantity > 0
    && product.price < 10
})
console.log(products);//[{name:"celery",type:"vegetable",quantity:30,price:8}]


//3.假定有两个数组(A,B),根据A中id值,过滤掉B数组不符合的数据
var post = {id:4,title:"Javascript"};
var comments = [
   {postId:4,content:"Angular4"},
   {postId:2,content:"Vue.js"},
   {postId:3,content:"Node.js"},
   {postId:4,content:"React.js"},
];
function commentsForPost(post,comments){
   return comments.filter(function(comment){
     return comment.postId === post.id;
   })
}
console.log(commentsForPost(post,comments));//[{postId:4,content:"Angular4"},{postId:4,content:"React.js"}]

4.find返回通过测试(函数内判断)的数组的第一个元素的值

//假定有一个对象数组(A),找到符合条件的对象
var users = [
  {name:"Jill"},
  {name:"Alex",id:2},
  {name:"Bill"},
  {name:"Alex"}
 ];
// es5方法
 var user;
 for(var i = 0; i < users.length; i++){
  if(users[i].name === "Alex"){
    user = users[i];
    break;//找到后就终止循环
  }
 }
 console.log(user);// {name:"Alex",id:2}
 // es6 find
 user = users.find(function(user){
   return user.name === "Alex";
 })
 console.log(user);// {name:"Alex",id:2}找到后就终止循环
 
//2.假定有一个对象数组(A),根据指定对象的条件找到数组中符合条件的对象
var posts = [
 {id:3,title:"Node.js"},
 {id:1,title:"React.js"}
];
var comment = {postId:1,content:"Hello World!"};
function postForComment(posts,comment){
 return posts.find(function(post){
   return post.id === comment.postId;
 })
}
console.log(postForComment(posts,comment));//{id: 1, title: "React.js"}

5、every && some
every:数组中是否每个元素都满足指定的条件
some:数组中是否有元素满足指定的条件
总而言之:Some: 一真即真;Every: 一假即假

//ES6 some every
var every = computers.every(function(computer){
  return computer.ram > 16;
})
console.log(every);//false
var some = computers.some(function(computer){
 return computer.ram > 16;
})
console.log(some);//true

6.reduce:接收一个方法作为累加器,数组中的每个值(从左至右) 开始合并,最终为一个值

// 计算数组中所有值的总和
var numbers = [10,20,30];
 var sum = 0;
//es5 方法
for(var i = 0; i < numbers.length; i++){
  sum += numbers[i];
}
console.log(sum);
 // es6 reduce
var sumValue = numbers.reduce(function(sum2,number2){
 console.log(sum2);//0 10 30 60
 return sum2 + number2;
},0);//sum2初始值为0
console.log(sumValue);
//将数组中对象的某个属性抽离到另外一个数组中
var primaryColors = [
   {color:"red"},
   {color:"yellow"},
   {color:"blue"}
 ];
 var colors = primaryColors.reduce(function(previous,primaryColor){
    previous.push(primaryColor.color);
    return previous;
 },[]);
 console.log(colors);//["red", "yellow", "blue"]

对象遍历方法有哪些?
遍历对象所有的可枚举属性(自有的+继承的属性),使用 for…in
遍历对象自有的所有可枚举属性(非继承属性),使用 Object.keys() 或 for…in + Objec.hasOwnProperty()
获取对象所有继承属性(非自有属性),可以使用 for…in + Object.keys()
遍历对象自有的所有可枚举和不可枚举属性(非继承属性),使用 Object.getOwnPropertyNames()
获取对象自有的所有可枚举、不可枚举属性和继承属性,使用 for…in + Object.getOwnPropertyNames(obj) 或 for…in + Object.keys() + Object.getOwnPropertyNames(obj)
JS转数据类型方法有哪些?
使用转换函数、强制类型转换、利用js变量弱类型特性进行转换
Number()转换数值,string转换字符串,boolean转换布尔类型
undefined,null 和 undeclared 有什么区别?
a、null表示"没有对象",即该处不应该有值,转为数值时为0。典型用法是:作为函数的参数,表示该函数的参数不是对象。作为对象原型链的终点。
b、undefined表示"缺少值",就是此处应该有一个值,但是还没有定义,转为数值时为NaN。典型用法是:变量被声明了,但没有赋值时,就等于undefined。调用函数时,应该提供的参数没有提供,该参数等于undefined。对象没有赋值的属性,该属性的 值为undefined。函数没有返回值时,默认返回undefined。
c、undeclared:js语法错误,没有申明直接使用,js无法找到对应的上下文。
new操作符具体干了什么呢?
1.创建一个空对象

let obj=new Object();

2.链接到原型
把obj的proto指向构造函数Func的原型对象prototype,此时便建立了obj对象的原型链:obj->Func.prototype->Object.prototype->null

obj.__proto__=Func.prototype;

3.绑定this值(让Func中的this指向obj,并执行Func的函数体)

let result=Func.call(obj);

4.返回新对象(判断Func的返回值类型:如果无返回值或者返回一个非对象值,则将obj作为新对象返回;否则会将result作为新对象返回)

if(typeof(result)=="object"){
func=result;
}else{
func=obj;
}

至少3种用JS跳转页面的方法?

//1.指定调转的地方
window.location.href='url'
//2.参见的浏览器返回上一个已访问的页面,直到访问最初访问的页面
window.history.back(-1);
//3.navigate对象包含有关浏览器的信息,也可以作为页面跳转,后面直接加要跳转的地方
window.navigate("url")
//4.当页面内有框架时,指定最顶层的窗口跳转,以及包含框架的最外层的浏览器
top.location="url"

怎么获取浏览器窗口的可视高度?

alert($(window).height()); //浏览器时下窗口可视区域高度

alert($(document).height()); //浏览器时下窗口文档的高度
alert($(document.body).height());//浏览器时下窗口文档body的高度
alert($(document.body).outerHeight(true));//浏览器时下窗口文档body的总高度 包括border padding margin
alert($(window).width()); //浏览器时下窗口可视区域宽度
alert($(document).width());//浏览器时下窗口文档对于象宽度
alert($(document.body).width());//浏览器时下窗口文档body的高度
alert($(document.body).outerWidth(true));//浏览器时下窗口文档body的总宽度 包括border padding margin
 
alert($(document).scrollTop()); //获取滚动条到顶部的垂直高度
alert($(document).scrollLeft()); //获取滚动条到左边的垂直宽度

什么是事件委托?
事件委托也称之为事件代理(Event Delegation)。是JavaScript中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡
一个事件触发后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。
(1)捕获阶段:从window对象传导到目标节点(上层传到底层)称为“捕获阶段”(capture phase),捕获阶段不会响应任何事件;
(2)目标阶段:在目标节点上触发,称为“目标阶段”
(3)冒泡阶段:从目标节点传导回window对象(从底层传回上层),称为“冒泡阶段”(bubbling phase)。事件代理即是利用事件冒泡的机制把里层所需要响应的事件绑定到外层。
如何在JS中编码和解码 URL
escape 和 unescape
*escape()*不能直接用于URL编码,除了ASCII字母、数字、标点符号"@ * _ + - . /“以外,对其他所有字符进行编码,它的真正作用是返回一个字符的Unicode编码值.对应的解码函数是unescape()。
注意点:
Javascipt函数的输入和输出,默认都是Unicode字符
*escape()*不对”+“编码,服务器处理数据的时候,会把+号处理成空格
encodeURI 和 decodeURI
它着眼于对整个URL进行编码,因此除了常见的符号以外,对其他一些在网址中有特殊含义的符号”; / ? : @ & = + $ , #“,也不进行编码。编码后,它输出符号的utf-8形式,并且在每个字节前加上%。
它对应的解码函数是decodeURI()
encodeURIComponent 和decodeURIComponent
它用于对URL的组成部分进行个别编码,而不用于对整个URL进行编码。
因此,”; / ? : @ & = + $ , #",这些在encodeURI()中不被编码的符号,在encodeURIComponent()中统统会被编码。至于具体的编码方法,两者是一样。
前端存储有哪些、特点、项目中应用场景?
存储方式:cookie,sessionStorage,localStaorage,indexedDB

COOKIE常用属性:
Expires 用于设置 Cookie 的过期时间
Max-Age 用于设置在 Cookie 失效之前需要经过的秒数(优先级比Expires高)
Domain指定了 Cookie 可以送达的主机名
Path指定了一个 URL路径,这个路径必须出现在要请求的资源的路径中才可以发送 Cookie 首部
区别:
cookie在浏览器和服务器间来回传递。sessionStorage和localStorage不会;
sessionStorage和localStorage的存储空间更大;
sessionStorage和localStorage有更多丰富易用的接口;
sessionStorage和localStorage各自独立的存储空间;
cookie是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。
cookie数据始终在同源的http请求中携带(即使不需要),即会在浏览器和服务器间来回传递。
sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存
有效时间:
localStorage:存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
sessionStorage:数据在当前浏览器窗口关闭后自动删除
cookie:设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭

localstorage存储:只能存入字符串,无法直接存对象
设置:localStorage.setItem(‘Name’,‘value’);
获取:localStorage.getItem(‘Name’);
获取键名:localStorage.key(0);
删除:localStorage.removeItem(‘Name’)
一次性清除所有存储:localStorage.clear();
session:会话关闭,消息移除
应用场景:
1、标记用户与跟踪用户行为的情况,推荐使用cookie
2、适合长期保存在本地的数据(令牌),推荐使用localStorage
3、敏感账号一次性登录,推荐使用sessionStorage
4、存储大量数据的情况、在线文档(富文本编辑器)保存编辑历史的情况,推荐使用indexedDB
对闭包的看法,为什么要用闭包?说一下闭包原理以及应用场景?
闭包是有权访问另一个函数私有变量的函数叫闭包。
使用闭包,一可以读取函数中的变量,二可以将函数中的变量存储在内存中,保护变量不被污染。而正因闭包会把函数中的变量值存储在内存中,会对内存有消耗,所以不能滥用闭包,否则会影响网页性能,造成内存泄漏。当不需要使用闭包时,要及时释放内存,可将内层函数对象的变量赋值为null。
闭包原理:
函数执行分成两个阶段(预编译阶段和执行阶段)。
在预编译阶段,如果发现内部函数使用了外部函数的变量,则会在内存中创建一个“闭包”对象并保存对应变量值,如果已存在“闭包”,则只需要增加对应属性值即可。
执行完后,函数执行上下文会被销毁,函数对“闭包”对象的引用也会被销毁,但其内部函数还持用该“闭包”的引用,所以内部函数可以继续使用“外部函数”中的变量
利用了函数作用域链的特性,一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域链中,函数执行完毕,其执行作用域链销毁,但因内部函数的作用域链仍然在引用这个活动对象,所以其活动对象不会被销毁,直到内部函数被烧毁后才被销毁。
优点:
1.可以从内部函数访问外部函数的作用域中的变量,且访问到的变量长期驻扎在内存中,可供之后使用
2.避免变量污染全局
3.把变量存到独立的作用域,作为私有成员存在
缺点:
1.对内存消耗有负面影响。因内部函数保存了对外部变量的引用,导致无法被垃圾回收,增大内存使用量,所以使用不当会导致内存泄漏
2.对处理速度具有负面影响。闭包的层级决定了引用的外部变量在查找时经过的作用域链长度
3.可能获取到意外的值(captured value)
应用场景:
应用场景一: 典型应用是模块封装,在各模块规范出现之前,都是用这样的方式防止变量污染全局

var Test = (function () {
    // 这样声明为模块私有变量,外界无法直接访问
    var foo = 0;

    function Test() {}
    Test.prototype.bar = function bar() {
        return foo;
    };
    return Test;
}());

应用场景二: 在循环中创建闭包,防止取到意外的值

//如下代码,无论哪个元素触发事件,都会弹出 3。因为函数执行后引用的 i 是同一个,而 i 在循环结束后就是 3
for (var i = 0; i < 3; i++) {
    document.getElementById('id' + i).onfocus = function() {
      alert(i);
    };
}
//可用闭包解决
function makeCallback(num) {
  return function() {
    alert(num);
  };
}
for (var i = 0; i < 3; i++) {
    document.getElementById('id' + i).onfocus = makeCallback(i);
}

原型链?
理解原型和原型链首先要知道几个概念:
①、在js里,继承机制是原型继承。继承的起点是 对象的原型(Object prototype)。
②、一切皆为对象,只要是对象,就会有 proto 属性,该属性存储了指向其构造的指针。
Object prototype也是对象,其 proto 指向null。
③、对象分为两种:函数对象和普通对象,只有函数对象拥有『原型』对象(prototype)。
prototype的本质是普通对象。
Function prototype比较特殊,是没有prototype的函数对象。
new操作得到的对象是普通对象。
④、当调取一个对象的属性时,会先在本身查找,若无,就根据 proto 找到构造原型,若无,继续往上找。最后会到达顶层Object prototype,它的 proto 指向null,均无结果则返回undefined,结束。
⑤、由 proto 串起的路径就是『原型链』。
总结:
第一句话:prototype是函数的原型对象,即prototype是一个对象,它会被对应的__proto__引用。
第二句话:要知道自己的__proto__引用了哪个prototype,只需要看看是哪个构造函数构造了你,那你的__proto__就是那个构造函数的prototype。
第三句话:所有的构造函数的原型链最后都会引用Object构造函数的原型,即可以理解Object构造函数的原型是所有原型链的最底层,即Object.prototype.__proto===null
怎么理解this的指向?怎么改变this的指向?
this指向:
1、通常在函数中的 this 指向的是调用函数的那个对象(谁调用指向谁)
2、事件函数中的 this 通常指向的是绑定事件的事件源元素
3、构造函数中的 this ,(使用 new 调用构造函数创建对象),通常指向的是 new 所创建出来的对象本身
4、全局范围的 this 通常指向的是全局对象(浏览器中是 window)
修改this指向:

Function.prototype.bind(thisArg) -- ES5
//能够返回一个新函数,该新函数的主体与原函数主体一致,但当新函数被调用执行时,函数体中的 this 指向的是 thisArg 所表示的对象

Function.prototype.call(thisArg, val1, val2, ....)
//调用函数执行,在函数执行时将函数体中的 this 指向修改为 thisArg 所表示的对象
//val1, val2, .... 表示传递给调用函数的实际参数列表

Function.prototype.apply(thisArg, array|arguments)
//调用函数执行,在函数执行时将函数体中的 this 指向修改为 thisArg 所表示的对象,
//array|arguments 表示调用函数的参数列表,使用数组或类数组的格式

如何区分变量是数组还是对象?
方法一:通过判断变量的类型,并且变量的length属性(除了有一种例外是arguments对象–当给函数传参时数据存储的地方)
方法二:使用toString方法将对象转换成其他类型的string
方法三:ECMAScript 5中可以使用isArray来判断
方法四:使用isPrototypeOf()函数
原理:检测一个对象是否是Array的原型(或处于原型链中,不但可检测直接父对象,还可检测整个原型链上的所有父对象)
使用方法: parent.isPrototypeOf(child)来检测parent是否为child的原型;
需注意的是isPrototypeOf()函数实现的功能和instancof运算符非常类似;
方法五:使用constructor属性
方法六:使用concat方法–灵活变通
array.concat(数组1,数组2,…)
返回一个新数组,这个新数组是由两个或更多数组组合而成的
ECMAScript 2015(ES6)有哪些新特性?
箭头操作符 =>;
对类class的支持(constructor构造函数);
不定参数…x;let和const关键字;
for of遍历;
模块的支持import;
解构赋值;
展开(…)运算符
promise异步函数的处理模式(pending等待中;resolve返回成功,reject返回失败);
介绍下 Set、Map的区别?
1.Map是键值对,Set是值得集合,当然键和值可以是任何的值;
2.Map可以通过get方法获取值,而set不能因为它只有值;
3.都能通过迭代器进行for…of遍历;
4.Set的值是唯一的可以做数组去重,Map由于没有格式限制,可以做数据存储;

Map:Map对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。构造函数Map可以接受一个数组作为参数。

map对应的数据类型是对象{},它拥有和对象一样的方法;
map的键和值可以是任何对象,这一点对象的键只能是number或者string;
自带iterator遍历器,可以进行for...of遍历;
初始化一个Map: var map = new Map([[1],[2]]);
对应的方法:
size:返回Map对象中所包含的键值对个数
set(key, val): 向Map中添加新元素
get(key): 通过键值查找特定的数值并返回
has(key): 判断Map对象中是否有Key所对应的值,有返回true,否则返回false
delete(key): 通过键值从Map中移除对应的数据
clear(): 将这个Map中的所有元素删除
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员
Set:Set对象允许你存储任何类型的值,无论是原始值或者是对象引用。它类似于数组,但是成员的值都是唯一的,没有重复的值。

set对应的数据类型是数据,有一些方法可以公用;
由于map是值的集合,所有set的键和值是相等的;
set所有的值是唯一的,可以进行数组去重;
自带iterator遍历器,可以进行for...of遍历;
初始化一个Set:var set = new Set(['1',undefined,{},2,[3,4]]);
对象的方法:
size:返回Map对象中所包含的键值对个数
add(value):添加某个值,返回 Set 结构本身(可以链式调用)。
delete(value):删除某个值,删除成功返回true,否则返回false。
has(value):返回一个布尔值,表示该值是否为Set的成员。
clear():清除所有成员,没有返回值。
keys():返回键名的遍历器。
values():返回键值的遍历器。
entries():返回键值对的遍历器。
forEach():使用回调函数遍历每个成员。

如何取一个1~10的随机数
var num=Math.floor(Math.random()*10+1);
使用async、await如何捕获异常?
引入async、await,便于异步编程
async、await避免了js的回调地狱问题

 //async:作为一个关键字放到函数前面,用于表示函数是一个异步函数,异步函数意味着该函数的执行不会阻塞后面代码的运行
   // await表示等待,后面可以放任何表达式,不过更多的是放一个返回promise对象的表达式(async和await需一起使用)
//例如:
// 角色的编辑
    async editRole(id) {
      // 数据回显
      this.roleForm = await getRoleDetail(id)
      // 弹窗出现
      this.showDialog = true
    }
   //代码解析:在代码的执行过程中,调用editRole函数,在里面遇到了await,await表示等一下,于是代码就在这里暂停一下,不在向下执行,等待后面的promise对象执行完毕,拿到它的返回值之后,赋值给this.roleForm,暂停结束,代码继续执行,弹窗出现
    //异常的处理:通过try/catch捕获异常,把await放到try中进行执行,如有异常,就使用catch进行处理
//例如:
// 删除员工
    async deleteEmployee(id) {
      try {
        await this.$confirm('您确定删除该员工吗')
        await delEmployee(id)
        this.getEmployeeList()
        this.$message.success('删除员工成功')
      } catch (error) {
        console.log(error)
      }
    }

错误处理:
使用 promises 的情况下,一个异步函数会返回两种可能的值:resolved 和 rejected。我们可以使用 .then() 来处理正常的情况 .catch() 处理异常情况。
使用async/await的情况下,则使用try…catch,当 await 一个函数调用的时候,任何 rejected 的值都会以异常的形式抛出来
var、let、const区别
var定义的变量可以修改,如果不初始化会输出undefined,不会报错。
const定义的变量不可以修改,而且必须初始化。不然报错。
let是块级作用域,函数内部使用let定义后,对函数外部无影响。

// const k; // 报错
const k = 100;
// const k = 200; // 报错
var i = 99;

function test() {
    // console.log(i); // 报错
    let i = 10;
    console.log(i);
}
test() // 10 
console.log(i) //99

如何获取对象的key名?
使用for in遍历对象时,需要用hasOwnProperty(key)方法过滤掉非对象自身的属性(继承自原型链的属性)

var obj = {
  "name" : "suyan",
  "age" : 24,
}
for(var key in obj){  //遍历对象的所有属性,包括原型链上的所有属性
  if(obj.hasOwnProperty(key){ //判断是否是对象自身的属性,而不包含继承自原型链上的属性
    console.log(key);        //键名"name","age"
    console.log(arr[key]);   //键值"suyan",24
     }
}

什么是响应式设计?响应式设计的基本原理是什么?如何兼容低版本的IE
响应式设计就是网站能够兼容多个终端,而不是为每个终端做一个特定的版本
基本原理是利用CSS3媒体查询,为不同尺寸的设备适配不同样式
对于低版本的IE,可采用JS获取屏幕宽度,然后通过resize方法来实现兼容:

$(window).resize(function () {
  screenRespond();
});
screenRespond();
function screenRespond(){
var screenWidth = $(window).width();
if(screenWidth <= 1800){
  $("body").attr("class", "w1800");
}
if(screenWidth <= 1400){
  $("body").attr("class", "w1400");
}
if(screenWidth > 1800){
  $("body").attr("class", "");
}
}

面向对象和面向过程的理解?
1.面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了
2.面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为
3.面向对象是以功能来划分问题,而不是步骤:基本思想是使用对象,类,继承,封装等基本概念来进行程序设计
说说Typescripy和Javascript的区别?
JavaScript是一种弱类型语言动态类型,弱类型语言多余小项目来说比较灵活,但是对于大项目来说,过于灵活会增加项目的复杂度,程序员维护起来比较困难
Typescript语言则是JavaScript的超集
可以编译成JavaScript执行,他的最大特点就是支持强类型,有编译类型检查,这为程序员编写程序带来了极大方便
JavaScript和Typescript的区别
typescript完全兼容javascript,它可以编译成javascript
typescript有编译时类型检查,这为程序的编写带来了极大的方便
javascript是一门动态语言,而typescript添加了可选的静态类型
typescript在javascript的基础上增加了不少特性

Typescript有哪些基础类型?

原始数据类型有以下六种:

boolean 布尔值
number 数值
string 字符串
null 空值
undefined 未定义
Symbol (ES6 中的新类型)

非原始数据类型有以下九种:

数组
Tuple 元祖
enum 枚举
never 永不存在的值的类型
void
any 任意类型
联合类型
函数类型
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值