1、有无序的一组数据,采用2中方式,将该数据从大到小进行排序
// 快速排序
var quicksort = function(arr){
if(arr.length<=1){
return arr;
}
//取中间值作为一个标杆进行比较
var midIndex=Math.floor(arr.length/2);
var midIndexVal=arr.splice(midIndex,1);
//新建两个数组存放比中间值大的或者小的
var left=[];
var right=[];
for(var i=0;i<arr.length;i++){
if(arr[i]<midIndexVal){
//如果比中间值小放在左面
left.push(arr[i]);
}else{
//如果比中间值大放在右面
right.push(arr[i]);
}
}
//依次将两边的数组在调用quicksort函数最后进行concat连接数组
return quicksort(left).concat(midIndexVal,quicksort(right));
}
var arr = [3,38,5,44,15,36,26,27,2,46,4,47,19,50,48]
var newArr = quicksort(arr).reverse()
console.log(newArr);
// [50, 48, 47, 46, 44, 38, 36, 27, 26, 19, 15, 5, 4, 3, 2]
//冒泡
var temp = 0;
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j + 1]; arr[j + 1] = arr[j]; arr[j] = temp;
}
}
}
console.log(arr.reverse());
// sort
let arr = [3,38,5,44,15,36,26,27,2,46,4,47,19,50,48]
let newArr=arr.sort(function (a, b) { return b-a })
console.log(newArr)
2、null 和 undefined的区别
3、css中link和@import的区别
建议使用link标签,慎用@import方式。
1.从属关系区别
@import是 CSS 提供的语法规则,只有导入样式表的作用;link是HTML提供的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等。
2.加载顺序区别
加载页面时,link标签引入的 CSS 被同时加载;@import引入的 CSS 将在页面加载完毕后被加载。
3.兼容性区别
@import是 CSS2.1 才有的语法,故只可在 IE5+ 才能识别;link标签作为 HTML 元素,不存在兼容性问题。
4.DOM可控性区别
可以通过 JS 操作 DOM ,插入link标签来改变样式;由于 DOM 方法是基于文档的,无法使用@import的方式插入样式。
5.权重区别(该项有争议,下文将详解)
link引入的样式权重大于@import引入的样式。
https://www.cnblogs.com/my--sunshine/p/6872224.html
4、var arr1 =[1,2,3,4,[5,6,7]] 转换 [1,2,3,4,5,6,7]
https://blog.csdn.net/ddwddw4/article/details/96313380
// 第一种
let arr = [1,2,3,[4,5,6,7]]
console.log(arr.join().split(',').map(item => +item))
// 第二种
console.log(arrs.flat(Infinity))
// flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
//使用 Infinity 作为深度,展开任意深度的嵌套数组
arr3.flat(Infinity);
// [1, 2, 3, 4, 5, 6]
//flat() 方法会移除数组中的空项:
var arr4 = [1, 2, , 4, 5];
arr4.flat();
// [1, 2, 4, 5]
// 第三种
let arr = [1, 2, 3, 4, 5, [6, 7, 8, [9, 10, 11, 12, [13, 14, 15, 16]]]]
console.log(arr.toString()) // 输出为:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
let newArr = arr.toString().split(',')
console.log(newArr) // 输出为:["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"]
//第四种
let arr = [1, 2, 3, 4, 5, [6, 7, 8, [9, 10, 11, 12, [13, 14, 15, 16]]]]
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])
}
}
}
arrConversion(arr)
console.log(newArr) // 输出:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
5、解析答案所输入的值
var a=14;
(function () {
var a= b =10;
console.log('1',a,b) //10 10
})()
console.log('2', a,b) //14 10
6、数组的去重
https://blog.csdn.net/ddwddw4/article/details/84401353
7、[1,2,3,5,7,8,10,13,14] 打印出
const num1 = [1,2,3,5,7,8,10,13,14]
function simplieStr(num){
let result = []
let temp = num[0]
num.forEach((value,index) => {
if(value+1 !== num[index+1]) {
if(temp !== value) {
result.push(`${temp}~${value}`)
}else {
result.push(`${value}`)
}
temp = num[index+1]
}
})
return result
}
console.log(simplieStr(num1).join(','))
8、编程题,写个程序把 entry 转换成如下对象
ar entry = {
a: {
b: {
c: {
dd: 'abcdd'
}
},
d: {
xx: 'adxx'
},
e: 'ae'
}
}
// 要求转换成如下对象
var output = {
'a.b.c.dd': 'abcdd',
'a.d.xx': 'adxx',
'a.e': 'ae'
}
var entry = {
a: {
b: {
c: {
dd: 'abcdd'
}
},
d: {
xx: 'adxx'
},
e: 'ae'
}
}
function flatObj(obj,parentKey = "",result={}) {
for(const key in obj) {
if(obj.hasOwnProperty(key)) {
let keyName = `${parentKey}${key}`;
if(typeof obj[key] === 'object') {
flatObj(obj[key],keyName+ '.',result)
}else {
result[keyName] = obj[key]
}
}
}
return result;
}
console.log(flatObj(entry))
9: Vue中的 computed 和 watch的区别
computed
computed看上去是方法,但是实际上是计算属性,它会根据你所依赖的数据动态显示新的计算结果。计算结果会被缓存,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算
1)下面是一个比较经典简单的案例
<template>
<div class="hello">
{{fullName}}
</div>
</template>
<script>
export default {
data() {
return {
firstName: '飞',
lastName: "旋"
}
},
props: {
msg: String
},
computed: {
fullName() {
return this.firstName + ' ' + this.lastName
}
}
}
</script>
注意
在Vue的 template模板内({{}})是可以写一些简单的js表达式的很便利,如上直接计算 {{this.firstName + ’ ’ + this.lastName}},因为在模版中放入太多声明式的逻辑会让模板本身过重,尤其当在页面中使用大量复杂的逻辑表达式处理数据时,会对页面的可维护性造成很大的影响,而 computed 的设计初衷也正是用于解决此类问题。
应用场景
适用于重新计算比较费时不用重复数据计算的环境。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。如果一个数据依赖于其他数据,那么把这个数据设计为computed
watch
watcher 更像是一个 data 的数据监听回调,当依赖的 data 的数据变化,执行回调,在方法中会传入 newVal 和 oldVal。可以提供输入值无效,提供中间值 特场景。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。如果你需要在某个数据变化时做一些事情,使用watch。
<template>
<div class="hello">
{{fullName}}
<button @click="setNameFun">click</button>
</div>
</template>
<script>
export default {
data() {
return {
firstName: '飞',
lastName: "旋"
}
},
props: {
msg: String
},
methods: {
setNameFun() {
this.firstName = "大";
this.lastName = "熊"
}
},
computed: {
fullName() {
return this.firstName + ' ' + this.lastName
}
},
watch: {
firstName(newval,oldval) {
console.log(newval)
console.log(oldval)
}
}
}
</script>
总结:
1.如果一个数据依赖于其他数据,那么把这个数据设计为computed的
2.如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化】
10 已知数组编写一个程序将数组扁平化去除其中重复的数,最终的一个升序且不重复的数组
var arr = [11,22,33,[13,14,15,15, [16,17,18,19,[11,12,[13,12]]]],12];
var newArr =Array.from(new Set(arr.flat(Infinity))).sort((a,b) => a-b)
console.log
11、 target1 === target2条件成立?
A、
const target1 = {a:1,b:2,c:3}
const target2 = {…target1} //false
B、
const target1 = {a:1,b:2,c:3}
const target2 = target1
target2.d = 4
console.log(target1) // {a:1,b:2,c:3,d:4}
console.log(target2) // {a:1,b:2,c:3,d:4} true
C、
const target1 = [1,2,3]
const target2 = target1
target2[3] =4
console.log(target1) // [1,2,3,4]
console.log(target2) // [1,2,3,4] true
D、
const target1 = [3,2,1]
const target2 = target1.sort()
console.log(target1) // [1,2,3]
console.log(target2) // [1,2,3] true
12输出的结果是什么
console.log([]+{}) // ‘[object object]’
解释:
js在进行加法运算的时候, 会先推测两个操作数是不是number,如果是,则直接相加得出结果。
如果其中有一个操作数为string,则将另一个操作数隐式的转换为string,然后进行字符串拼接得出结果。
如果操作数是像boolean这种的简单数据类型,那么就将操作数转换为number相加得出结果
如果操作数为对象或者是数组这种复杂的数据类型,那么就将两个操作数都转换为字符串,进行拼接
[] + {},这是两个复杂数据结构相加的例子
我们先将两个操作数转换为string,然后进行拼接
[] -----> ' '
{} -----> '[object Object]'
[] + {} = '[object Object]'
console.log({}+[]) // 0
原因是有的js解释器会将开头的 {} 看作一个代码块,而不是一个js对象,于是真正参与运算的是+[],就是将[]转换为number,于是得出答案0
{} + []的结果是相当于+[],结果是0数字类型。
13 实现一个函数add,满足下列输出结果
add(1) //1
add(1)(2) // 3
add(1)(2)(3) // 6
add(1)(2,3) // 6
add(1,2)(3) // 6
add(1,2,3) // 6
function add () {
let args = [...arguments]
let fn = function() {
args.push(...arguments)
return fn
}
fn.toString = function() {
return args.reduce((x,y) => x+y)
}
return fn
}
14垃圾处理机制
参考《js高级程序设计》
垃圾处理机制的原理:找到那些不再继续使用的变量,然后释放他占用的内存。
为此,垃圾收集器会按照固定的时间间隔(或代码中预定的收集时间)周期性地执行这个操作。
例如局部环境变量,在使用完之后可能无用,垃圾回收器跟踪变量是否有用,对不再有用的变量标记,以备将来回收。主要是使用标记清除,ie还会使用引用计数。
浏览器做法:
1.标记清除
主要思想是给当前不使用的值加上标记,然后再回收他的内存。
2.引用计数
跟踪记录所有值被引用的次数。ie中访问原生js对象这种算法会导致性能问题。代码中存在循环引用对象时这个算法也会导致问题。
其他浏览器已经废弃使用。
写代码做法:
3.解除变量的引用
为了确保有效的回收内存,应该及时解除不再使用的全局对象,全局对象的属性,以及循环引用变量的引用。
进行管理内存,做法:
解除引用:一旦数据不再使用,最好通过将值设为null来释放其引用。
解除引用不意味着自动回收改值所占的内存,解除引用的真正作用是让值脱离执行环境,以便垃圾回收器下次运行时将其收回。
15、编程题,找出字符串中连续出现最多的字符和个数
比如:
‘abcaakjbb’ => {‘a’:2,‘b’:2}
‘abbkejsbcccwqaa’ => {‘c’:3}
注意:题目说的是连续出现,注意连续二字
function getStrMaxLengthObj(str) {
if (!str) {
return {}
}
let strObj = {}
let res = {}
let max = 0
let currentLetter = ''
for (let i = 0; i < str.length; i++) {
let item = str[i]
if (currentLetter === item) {
strObj[item] += 1
} else {
currentLetter = item
strObj[item] = 1
}
if (strObj[item] > max) {
max = strObj[item]
res = {}
res[item] = max
} else if (strObj[item] === max) {
res[item] = max
}
}
return res
}
console.log(getStrMaxLengthObj('1111114225555555553444463111116')) //- {5:9}
16、封装一个方法:把URL参数解析为一个对象,来获取地址栏url里面的传递的参数
function getUrlkey(url){
var params = {},
arr = url.split("?");
if (arr.length <= 1)
return params;
arr = arr[1].split("&");
for(var i=0, i<arr.length; i++){
var a = arr[i].split("=");
params[a[0]] = a[1];
}
return params;
}
var url = "http://www.baidu.com?key0=0&key1=1&key2=2",
ps = getUrlkey(url);
console.log(ps["key2"])
17、介绍下 http1.0、1.1、2.0 协议的区别
1.0 | 1.1 | 2.0 | |
---|---|---|---|
长连接 | 需要使用keep-alive 参数来告知服务端建立一个长连接 | 默认支持 | 默认支持 |
HOST域 | ✘ | √ | √ |
多路复用 | ✘ | - | √ |
数据压缩 | ✘ | ✘ | 使用HAPCK算法对header数据进行压缩,使数据体积变小,传输更快 |
服务器推送 | ✘ | ✘ | √ |
http/1 :
默认不支持长连接,需要设置keep-alive参数指定
强缓存expired、协商缓存last-modified\if-modified-since 有一定的缺陷
http 1.1 :
默认长连接(keep-alive),http请求可以复用Tcp连接,但是同一时间只能对应一个http请求(http请求在一个Tcp中是串行的)
增加了强缓存cache-control、协商缓存etag\if-none-match 是对http/1 缓存的优化
http/2 :
多路复用,一个Tcp中多个http请求是并行的 (雪碧图、多域名散列等优化手段http/2中将变得多余)
二进制格式编码传输
header压缩
服务端推送
18、ES6 中 Promise 的面试题
https://blog.csdn.net/FE_dev/article/details/83278508
19、前端性能优化
https://mp.weixin.qq.com/s/ZOa30LA5ueotS2mWfElPHw
20、永久性重定向(301)和临时性重定向(302)对 SEO 有什么影响
1)301 redirect——301代表永久性转移(Permanently Moved),301重定向是网页更改地址后对搜索引擎友好的最好方法,只要不是暂时搬移的情况,都建议使用301来做转址。
如果我们把一个地址采用301跳转方式跳转的话,搜索引擎会把老地址的PageRank等信息带到新地址,同时在搜索引擎索引库中彻底废弃掉原先的老地址。旧网址的排名等完全清零
(2)302 redirect——302代表暂时性转移(Temporarily Moved ),在前些年,不少Black Hat SEO曾广泛应用这项技术作弊,目前,各大主要搜索引擎均加强了打击力度,象Google前些年对Business.com以及近来对BMW德国网站的惩罚。即使网站客观上不是spam,也很容易被搜寻引擎容易误判为spam而遭到惩罚。