面试总结

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.01.12.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而遭到惩罚。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值