0. Предисловие
Много ли вы видели эту перспективу в группе фронтенда: как это сделать? Как получить эти данные? Как обновить весь список?
Ответ: Цикл! Траверс! Сохранить с массивом, траверс! jquery! вью!
Тогда есть несколько более продвинутых: я думаю, более быстрые обходные пути. Я хочу использовать метод с более высокой производительностью.
Ответ: рекурсия! Откройте новый массив, чтобы сохранить промежуточные переменные, а затем перейдите! document.querySelectorAll получить все, кэшировать длину, все элементы, пройти! Быстрый ряд, ставь маленькое слева, а большое справа, рекурсивно!
Затем, когда вы обнаружите, что водная группа — неразрешимая проблема, вы сделали продвинутый шаг. Спросите в группе, если это не кучка знакомых, а если они все незнакомые, то это слишком просто и люди думают, что они безмозглые, слишком сложно, люди думают, что это хлопотно, или они вообще не знают, и это можно сделать с помощью небольшого исследования. Поэтому в группе, полной незнакомых людей, лучше сделать это самостоятельно, если вы спросите других, вы можете ответить на вопрос, или решить его в насильственном цикле, или использовать какие-то другие термины, чтобы заставить его (например, некоторые библиотеки js которые малоизвестны, проверьте оригинал — это небольшая функция).
1. Я хочу привязать событие к каждому li, нажмите на какое из них, чтобы напечатать соответствующий номер
Прохожий: Петля, привяжите событие к каждому ли. Это выглядит так: HTML:
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
</ul>
js:
var li = document.querySelectorAll('li')
for(var i = 0;i<li.length;i++){//大约有一半的人连个length都不缓存的
li[i].onclick = function (i) {//然后顺便扯一波闭包,扯一下经典面试题,再补一句let能秒杀
return function () {
console.log(i)
}
}(i)
}
Вопрос Мальчик: Тогда что, если я добавлю Li динамически?
Прохождение: то же самое, сколько вы добавляете, я буду петлен как много
Проблемный мальчик: Если у меня есть кнопка и я нажимаю ее, чтобы добавить ли, я хочу добиться этого эффекта, что мне делать?
Прохожий: А? То же самое, то есть при добавлении нового цикла for перепривязать событие
Проблемный мальчик: ...
Восстановление сцены:
html:
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
</ul>
<button onclick="addli()">add</button>
js:
//原来的基础上再多一个函数,然后热心地写下友好的注释
function addli(){
var newli = document.createElement('li')
newli.innerHTML = document.querySelectorAll('li').length;//先获取长度,把序号写进去
document.querySelectorAll('ul')[0].appendChild(newli)//加入
var li = document.querySelectorAll('li')
for(var i = 0;i<li.length;i++){//再绑一次事件
li[i].onclick = function (i) {
return function () {
console.log(i)
}
}(i)
}
}
Проблемный подросток видел, что функция реализована, но всегда чувствовал, что проблемы с таким количеством документов, что браузер очень неудобный, а еще слышал, что «манипулировать DOM очень дорого». Поэтому он пролистал информацию, узнал об объектно-ориентированном прокси-сервере событий и всю ночь писал свой собственный код. После окончания инцидента была уже полночь, поэтому я открыл журнал чата и взглянул на ответ прохожего с приподнятым уголком рта. Проблемный подросток посмотрел на код, который написал сам, и очень обрадовался, и сделал маленький шаг в жизни:
html:
<input type="number" id="input">
<button onclick="addli()">add</button>
js:
class Ul {
constructor () {
this.bindEvent = this.bindEvent()//缓存合适的dom n事件
this.ul = document.createElement('ul')
this.bindEvent(this.ul,'click',(e)=>{
console.log(e.target.innerHTML)
})
this.init = this.init()//单例模式,只能添加一个ul
this.init(this.ul)
this.counts = 0//li个数
}
bindEvent () {
if (window.addEventListener) {
return function (ele, event, handle, isBunble) {
isBunble = isBunble || false
ele.addEventListener(event, handle, isBunble)
}
} else if (window.attachEvent) {
return function (ele, event, handle) {
ele.attachEvent('on' + event, handle)
}
} else {
return function (ele, event, handle) {
ele['on' + event] = handle
}
}
}
appendLi (nodeCounts) {
this.counts += nodeCounts
var temp = ''
while (nodeCounts) {
temp += `<li>${this.counts - nodeCounts +1}</li>`
nodeCounts --
}
this.ul.innerHTML += temp
}
init () {//单例模式
var isappend = false
return function (node) {
if(!isappend){
document.body.appendChild(node)
isappend = true
}
}
}
}
var ul = new Ul()
function addli(){
if(!input.value){
ul.appendLi(1)
}else{
ul.appendLi(+input.value)
input.value = ''
}
}
2. Я хочу, чтобы несколько элементов div выглядели как флажки
То есть несколько дивов, щёлкните какой из них яркий, щёлкните другой, тот div, который в данный момент включён, тут же тускнеет, а только что нажатый загорается.
Прохожий: у каждого div есть два класса, и класс щелчка указывает, что на него нажали. Каждый раз, когда нажимается элемент div, он перебирает все элементы div, чтобы сбросить состояние до тестового класса, а затем превращает щелчок в щелчок. Итак, я быстро написал кусок кода
html:
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<div class="test"></div>
<div class="test"></div>
<div class="test"></div>
css:
.test{
width: 100px;
height: 100px;
background-color: #0f0;
margin: 10px
}
.click{
background-color: #f00
}
js:
var divs = $('.test')
divs.click(function(){
divs.each(function(){
this.className = 'test'
})
this.className = 'click'
})
Мальчик ответил на вопрос: я не знаю, что такое jQuery, но я думаю, что это должно быть написано так
var divs = document.querySelectorAll('.test')
window.onclick = (function () {
var pre
return function (e) {
if(pre !== undefined){
divs[pre].className = 'test'
}
pre = Array.prototype.indexOf.call(divs,e.target)
e.target.className = 'click'
}
})()
Прохожий: я не знаю, что вы делаете с событием и IIFE, и я предлагаю вам изучить jQuery
Проблемный мальчик (думая): Очевидно, что время выполнения консольного теста составляет около 0,26 мс, а мой метод — около 0,12 мс.Почему нужно использовать jQuery? Ничего, вернитесь и продолжайте учиться.
3. От 1000 до 5000 взять все числа, сумма которых равна 5
Проблемный мальчик: rt, ищу более быстрый способ
Прохожий:
Array(4000).fill(1001).map((v,i)=>v+i).filter(n=>(n+"").split("").reduce(((s,x)=>+x+s),0)==5)
Люди, которые едят дыни: Ого, Боже, метод слишком прост, его легко понять
Прохожий Б:
let temp = []
for(let i = 1000;i<=5000;i++){
temp.push(i.toString().split('').map(x=>+x).reduce((a,b)=>a+b,0) === 5&&i)
}
console.log(temp.filter(x=>x!==false))
Люди, которые едят дыни: когда мы сможем писать код, прекрасный как бог?
Прохожий: На самом деле ничего, он вообще не учитывает сложность алгоритма и не оптимизирует его.
Дорога высотой в один фут, черт высотой в один фут, а затем есть общий метод:
var f = (s, l) => --l ? Array(s+1).fill(0).map((_,i)=> f(s-i,l).map(v =>i+v)).reduce((x,s)=>[...s,...x],[]):[[s]];
f(5, 4).filter(s=>s[0]>0)
Подсчитано, что проблема подростков не полностью удовлетворена.Хотя ответом является короткое и гибкое использование es6 и API, метод все еще немного прост и безмозглен, и создаются избыточные циклы.
Слегка оптимизированная версия, количество циклов уменьшено до более чем 600: (помимо ореола загрузки ES6)
function f (_from, _to, _n) {
var arr = []
var _to = _to + ''
var len = _to.length
!function q (n, str) {
if( str.length === len) {//保证4位数
if(str.split('').reduce((s,x)=>+x+s,0) == _n && str[0] != '0'){//每一位加起来等于5
arr.push(+str)
}
return
}
for(var i = 0;i <= _n - n;i++){//分别是0、1、2、3、4、5开头的
q(i,i + '' + str)//一位一位地递归
}
}(~~_from/1000,'')
return arr
}
f (1000, 5000,5)
Читаемость, очевидно, намного хуже, но и время выполнения намного хуже:
- Одна строка ES6: 16,3310546875 мс
- для цикла: 40,275146484375 мс
- Оптимизированная версия: 1.171826171875 мс
4. Я получил возвращенные данные json из интерфейса, но мне нужно манипулировать этими данными, не загрязняя исходные данные
Прохожий за секунды ответил, не задумываясь: var data2 = data
Другой прохожий на некоторое время подумал: нет, сначала нужно сделать глубокую копию.
Проблемный мальчик: как сделать глубокую копию?
Какой-то прохожий: JSON.stringify, а затем JSON.parse
Проблемный мальчик: Спасибо, очень полезно
Любой, у кого есть хоть немного знаний, знает, что одна строка не может решить все проблемы с глубоким копированием. На следующий день проблемный мальчик вернулся: раньше я убегал копировать, начальник сказал, что убьет меня, а теперь все объектно-ориентированные объекты в проекте взорваны
Прохожий: Черт, я не верю, что есть что-то, что не может решить синтаксис и синтаксический анализ.
Еще один прохожий: Цепочка прототипов разорвана, undefined становится нулевым значением, циклическая ссылка неверна, а все объектно-ориентированные напрасны
Проблемный мальчик особенно беспомощен, и никто не приходит на помощь.Может быть, у Бога есть немного лучший справочный ответ, ожидающий, когда он обнаружит:
function copy (arr) {
var temp
if (typeof arr === 'number'||typeof arr === 'boolean'||typeof arr === 'string') {
return arr
}
if(Object.prototype.toString.call(arr) === "[object Array]" ){
temp = []
for(x in arr){
temp[x] = copy(arr[x])
}
return temp
}else if(Object.prototype.toString.call(arr) === "[object RegExp]"){
temp = arr.valueOf()
var str = (temp.global ? 'g' : '') +(temp.ignoreCase ? 'i': '')+(temp.multiline ? 'm' : '')
return new RegExp(arr.valueOf().source,str)
}else if(Object.prototype.toString.call(arr) === "[object Function]"){
var str = arr.toString();
/^function\s*\w*\s*\(.*\)\s*\{(.*)/m.test(str);
var str1 = RegExp.$1.slice(0,-1);
return new Function(str1)//函数有换行就出事,求更好的解决方法
}else if(Object.prototype.toString.call(arr) === "[object Date]"){
return new Date(arr.valueOf());
}else if(Object.prototype.toString.call(arr) === "[object Object]"){
try{
temp = JSON.parse(JSON.stringify(arr))
}catch(e){//环引用解决:取出环引用部分stringify再放回去
var temp1 = {},circle,result,reset = false,hash
function traverse (obj) {
for(x in obj){
if(!reset&&obj.hasOwnProperty(x)){
if(!temp1[x]){
temp1[x] = obj[x]
}else if(typeof obj[x] === 'object'&&typeof temp1[x] === 'object'){
try{
JSON.stringify(obj[x])
}catch(e){
circle = obj[x]
hash = new Date().getTime()
obj[x] = hash
break
}finally{
return traverse(obj[x])
}
}
if(typeof obj[x] === 'object'){
return traverse(obj[x])
}
}else if(reset){
if(obj[x] === hash){
obj[x] = circle
return
}
if(typeof obj[x] === 'object'){
return traverse(obj[x])
}
}
}
}
traverse(arr)
result = JSON.parse(JSON.stringify(arr))
reset = true
traverse(result)
traverse(arr)
temp = result
}finally{//考虑到原型链和Object.create(null)
if(arr.__proto__.constructor && arr.__proto__.constructor !== Object){
temp.__proto__.constructor = arr.__proto__.constructor
}
if(!arr.__proto__.constructor){
temp.__proto__.constructor = null
}
return temp
}
}
if(!arr){
return arr
}
}
5. Динамически добавлять элементы в массив, проверять суммирование, помогите пожалуйста
Приведенная картинка, вероятно, такая, выберите ли и подсчитайте его цену в сумму:
Я полагаю, что 50% людей будут такими, прохожий: vue, v-for display,computed
Некоторые люди даже написали код за 2 минуты:
html:
<script src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script>
<div id='app'>
<ul>
<li v-for="x in list">
{{x.price}}
<input type="checkbox" v-model="x.selected">
</li>
</ul>
<button @click="add">add</button>
{{sum}}
</div>
js:
new Vue({
el:'#app',
data(){
return {
list:[{price:1,selected:false},{price:2,selected:false},{price:3,selected:false}]
}
},
methods:{
add(){
this.list.push({price:1,selected:false})
}
},
computed:{
sum(){
return this.list.reduce((s,x)=>x.selected?+x.price+s:s,0)
}
})
Проблемный мальчик: наш проект не использует vue
Сразу же взорвался: блин, он вообще родной. Как ты пишешь без vue? В противном случае вы можете изменить этот модуль на vue...
Проблемный мальчик, мы используем объектно-ориентированный для этого модуля в нашем проекте и иногда используем lodash для библиотеки инструментов.
Взрыв снова: lodash? Что за черт? Сказал не понять. Курица этого блюда продолжает пикировать
Волна рекламы, глубокая копия lodash, которая в настоящее время считается самой совершенной глубокой копией.
Тогда давай продолжим, а потом вопрос мальчик задал вопрос про vue, а потом нырнул
Таким образом, вы можете угадать код, который хочет написать проблемный подросток:
html:
<ul id="app"></ul>
js:
app.addEventListener('change',(function(){
var lastpick = 0
return function (e) {//相信很多人是每次change后,用循环一个个加起来的
lastpick += e.target.checked?+e.target.value:-e.target.value
res.innerHTML = lastpick
}
})())
var list = [{price:1,selected:false},{price:2,selected:false},{price:3,selected:false}]
var append = ''
for(var i = 0;i<list.length;i++){
append += '<li><input type="checkbox" value='+list[i].price+'>'+list[i].price+'</li>'
}
app.innerHTML = append
6. Серверная часть не помогает мне с пейджингом, как можно упростить пейджинг во внешнем интерфейсе?
Проблемный мальчик: это из личного центра, данных не так много, и пользователи обычно просматривают все данные постранично, потому что эти данные о потреблении нужно читать полностью, чтобы понять ситуацию
Прохожий A: после получения всех данных извлеките элементы в соответствии с данными каждой страницы и количеством страниц в цикле for и вставьте соответствующий html и каждый раз проходите
Прохожий Б: Блин, этот бэкенд ест дерьмо, он даже не разрывает страницу.
Прохожий C: Конечно, грузится по запросу, не стоит грузить все сразу
Прохожий: используйте плагин подкачки jQuery
Так что группа друзей, которые усердно и с энтузиазмом отвечают на вопросы, сразу же написали ответ:
html:
每页数据<select id="app">
<option>2</option>
<option>3</option>
<option>4</option>
</select>
<div>
<button onclick="pre()">上一页</button>
<button onclick="next()">下一页</button>
<p>当前是<span id="current"></span>页</p>
<table>
<tbody id="content">
</tbody>
</table>
</div>
js:
var data = [1,2,3,4,5,6,7,8,9,10,11,12,13]//后端拿到的数据
var currentIndex = 1
var per = 2
app.onchange = function (e) {
per = e.target.value
update(1)//更改每页数据时候返回第一页
}
function pre() {
currentIndex = currentIndex > 1?currentIndex-1:currentIndex
update(currentIndex,per)
}
function next(){
currentIndex = currentIndex < Math.floor(data.length/per)+1?currentIndex+1:currentIndex
update(currentIndex,per)
}
window.onload = function () {
update()
}
function update(currentPage, perPage){
var currentPage = currentPage ||currentIndex
var perPage = perPage || per
var ctx = ''
for(var i = perPage*(currentPage-1);i<perPage*currentPage;i++){
if(data[i]!==undefined) ctx += '<tr><td>'+data[i]+'</td></tr>'
}
content.innerHTML = ctx
current.innerHTML = currentPage
}
Конечно, когда бэкэнд не помогает с пейджингом, объем данных обычно невелик, и описанный выше подход не представляет проблемы. Однако в этом сценарии пользователю нужны все данные браузера, поэтому пейджинг по запросу не осуществляется. Мы не должны зацикливаться, когда это нужно пользователю, поэтому для пользователя временная сложность равна n. Если он сначала разбивается на страницы, а затем извлекается напрямую, сложность равна 1. В этом сценарии он просматривает их все, поэтому мы сначала разбиваем на страницы, а затем извлекаем данные. Улучшенный js:
var data = [1,2,3,4,5,6,7,8,9,10,11,12,13]
var currentIndex = 1
var per = 2
var list = []
app.onchange = function (e) {
per = +e.target.value
getdatalist(per)
update(1)
}
function pre() {
console.time('pre')
currentIndex = currentIndex>1?currentIndex-1:currentIndex
update(currentIndex, per)
console.timeEnd('pre')
}
function next(){
console.time('next')
currentIndex = currentIndex < Math.floor(data.length/per)+1?currentIndex+1:currentIndex
update(currentIndex, per)
console.timeEnd('next')
}
window.onload = function () {
getdatalist(2)
update()
}
function getdatalist (per) {
var per = per || 2
list = []
var pages = ~~(data.length/per)+1
for(var i = 0;i<pages;i++){
var temp = ''
data.slice(i*per,i*per+per).forEach(function(item){
temp += '<tr><td>'+item+'</td></tr>'
})
list.push(temp)
}
}
function update(currentPage, perPage){
currentIndex = currentPage || 1
var perPage = perPage || per
content.innerHTML = list[currentIndex-1]
current.innerHTML = currentIndex
}
тест времени:
Затраты времени, когда пользователи переключают страницы
Цикл по запросу:
Перелистывание вперед:
С увеличением пейджинга преимущество раннего пейджинга во времени переключения становится все больше и больше. Конечно, в обычных условиях пользователи, как правило, не просматривают все данные, поэтому обычно лучше использовать пейджинг по требованию.
7. Мы собираемся провести лотерею, в которой требуется, чтобы в номере пользователя было два числа, а сумма 100 считалась выигрышной.
Проблема мальчика: случайные числа распределяются равномерно (но из строя), такие как 3, 2, 1, 4, 5, 7 вместо 5, 1, 6, 7, 8
Прохожий A: Один за другим цикл, а затем судья
let arr =[12,40,60,80,62,13,58,87]
let obj = {}
arr.map(item=>{
if(!obj[item]){
let val = 100-item
obj[item] = 1
if(arr.includes(val)){
obj[val] = 1
console.log(item,val)
}
}
})
Итак, кто-то немедленно позвонил по номеру 666. Однако этот ES6 немного расточительный. Проблемный подросток казался недовольным, говоря: Наш объем данных может быть немного большим.
Итак, есть двухуказательная версия:
function f(arr,res){
var l = arr.length
var p = ~~(l/2)
var i = p - 1
var j = p
var ishasresult = false
arr = arr.sort((a,b)=>a-b)
while(i >= 0 && j < l){
if(arr[i] + arr[j] > res){
i --
}else if(arr[i] + arr[j] < res){
j ++
}else{
ishasresult = true
break
}
}
return ishasresult
}
Предполагая, что сортировка быстрая, общая временная сложность равна nlogn+logn.
На самом деле с ES6 это быстрее:
var myset = new Set(arr);
arr.find(function(value, index, arr) {
return myset.has(100 - value);
})
тест времени:
Безмозглый цикл ES6: 2,419189453125 мс 2,35595703125 мс 1,330078125 мс
Двойной указатель: 0,0400390625 мс 0,0283203125 мс 0,0390625 мс
Упрощенный ES6: 0,1240234375 мс 0,10986328125 мс 0,092041015625 мс
8. Массивы добавляют элементы в начало, concat и unshift один за другим более эффективны
Прохожий A: unshift ведь специально добавлен в голову, concat для соединения массивов, алгоритм однозначно сложнее unshift, es6... Считается, что concat устранен.
Результаты теста:
Очевидно, что unshift и ... обходятся один за другим, а concat напрямую связан, и сложность равна 1. Но вам все равно нужно смотреть на реальную сцену, абсолютного исключения или замены не существует.
Суммировать
Есть ли знакомые переживания? Цикл, перемещение, а затем xxx, использование vue, использование jQuery xx и использование плагинов xx. Для тех, кто задает вопросы, они должны сначала четко выразить свои потребности и постараться быть как можно более подробным, а не просто сфотографировать и спросить.Если Baidu может полагаться на документы, спрашивать не нужно. Если это осмысленный вопрос, то каждый должен хорошо подумать и понять сценарии приложений других людей, а не безмозглые циклы, или напрямую кидать плагин xx, xx.js другим, потому что другие это понимают, просто хотят лучшего ответа или не глупый ответ. Конечно, если он чисто белый, это нормально.
Если это большая корова, может, в кругу друзей такого нет, и такой группы нет. Я тоже новичок, учусь полгода, и у меня нет опыта во многих сценариях применения. Но некоторые люди, проработав несколько лет, все равно пишут какой-то безмозглый код, а код выставляет напоказ разные детали и не занимается этим. Не то чтобы я не считаю, что они хуже меня, я просто чувствую, наверное, поэтому есть люди, которые проработали 10 лет и 1 год.
Кроме того, во время интервью вас часто спрашивают, для чего используются замыкания?В приведенном выше примере есть несколько классических приложений замыкания, поэтому во время собеседования не просто говорите, что такое замыкание, замыкание приведет к утечке памяти, а также Вы знаете, для чего используются замыкания, не более чем кеширование, каррирование, одноэлементный режим, модульность и защита внутренних переменных. Итак, спросите себя, использовали ли вы когда-нибудь замыкания, чтобы сделать что-то значимое, и говорили ли вы когда-нибудь что-то вроде «какой смысл иметь IIFE без причины»? Используете ли вы ES6 только для аббревиатуры или стремитесь к визуальной краткости кода, чтобы притвориться? Вы много играли в прокси и деконструкцию присваивания? Знаете ли вы, что async+ можно использовать для попытки, которая не может зафиксировать асинхронность? Ожидание захвата асинхронности является наиболее часто используемым установить для дедупликации?Нет ли других широко используемых, кроме шаблонов let, const, promise, async-await, ..., set, backticks + string?
Пожалуйста, указывайте источник при перепечатке, сlhytНаггетс