您的位置:首页 > 职场人生

前端面试(代码)

2017-03-24 12:45 309 查看


JS数组去重

Array.prototype.unique1 = function () {

var n = []; //一个新的临时数组

for (var i = 0; i < this.length; i++) //遍历当前数组
{

//如果当前数组的第i已经保存进了临时数组,那么跳过,

//否则把当前项push到临时数组里面

if (n.indexOf(this[i]) == -1)
n.push(this[i]);

}
return n;
}


Array.prototype.unique2 = function()
{

var n = {},r=[]; //n为hash表,r为临时数组

for(var i = 0; i < this.length; i++) //遍历当前数组
{

if (!n[this[i]]) //如果hash表中没有当前项
{

n[this[i]] = true; //存入hash表

r.push(this[i]); //把当前数组的当前项push到临时数组里面

}

}
return r;
}


Array.prototype.unique3 = function()
{

var n = [this[0]]; //结果数组

for(var i = 1; i < this.length; i++) //从第二项开始遍历
{

//如果当前数组的第i项在当前数组中第一次出现的位置不是i,

//那么表示第i项是重复的,忽略掉。否则存入结果数组

if (this.indexOf(this[i]) == i) n.push(this[i]);

}

return n;

}


arr = [...new Set(arr)]; //ES6新方法




js中for循环中的setTimeout()正常工作

我们希望每隔2秒依次输出1,2,3

for (var i = 1; i <= 3; i++) {
setTimeout(function () {
console.log(i);
},2000);
}


实际上却是,在间隔2秒后直接输出3个3。

原因在于计时器是共享一个i,当for循环结束时,i已经变成3,所以这时就会多次弹出3.所以通过定义一个函数来实现中介的作用,从而创建了变量的值的副本。

function doSetTimeout(i) {
setTimeout(function() { console.log(i); }, 2000);
}

for (var i = 1; i <= 3; ++i)
doSetTimeout(i);


这时虽然输出1,2,3,但却是间隔2秒后一次性输出,并未达到我们要求的每隔2秒输出一个要求。所以这时我们要调整setTimeout的时间间隔

function doSetTimeout(i) {
setTimeout(function() { console.log(i); }, 2000*i);
}

for (var i = 1; i <= 3; ++i)
doSetTimeout(i);




<SCRIPT LANGUAGE="JavaScript">
var bb = 1;
function aa(bb) {
bb = 2;
alert(bb);
};
aa(bb);
alert(bb);
</SCRIPT>


结果:依次弹出 2和1

分析:函数体内,bb并没有使用var来定义,按理说这个bb在预处理的时候应该是window的属性。但在这里,函数声明的时候,带了一个参数bb,也就是相当于在函数体内声明了var bb。所以,函数里的bb就是函数活动对象的属性。所以函数执行时会输出2。函数执行完后,函数的活动对象被销毁,也就是局部的这个bb被删除了,执行流进入到window,再输出bb,值就是1了。如果声明函数时,把参数那里的bb去掉,这段代码执行起来,结果就是弹出 2 2



有一个长度未知的数组a,如果它的长度为0就把数字1添加到数组里面,否则按照先进先出的队列规则让第一个元素出队。

分析:这道题主要是考核了数组的队列方法和栈方法。

a.length === 0 ? a.push(1) : a.shift();




var test = (
function(a) {
this.a = a;
return function(b) {         return this.a + b;     }
}
(function(a, b) {
return a;  }(1, 2)
)
);
console.log(test(4));


输出5,考查自执行函数和闭包



请把
<ul><li>第1行</li><li>第2行</li>...</ul>
(ul之间有10个li元素)插入body里面,注意:需要考虑到性能问题。

分析:这题主要考察了dom操作。插入节点操作的可以使用insertBefore和appendChild方法,随便用一个都行。但是,题目要求要考虑性能问题,这才是关键,因为,JavaScript操作dom的开销是很大的!提高性能就要减少dom操作。因此,我当时使用了下面的方法,只操作一次dom就够的了:

var lis = "";
var ul = document.createElement("ul");   //把li以字符串形式生成
for(var i = 1; i <= 10; i++) {
lis += "<li>第" + i + "行</li>";
}   // 最后通过innerHTML插入ul里面
ul.innerHTML = lis;   //这里才操作dom,把ul插入到body
document.body.appendChild(ul);




不使用loop循环,创建一个长度为100的数组,并且每个元素的值等于它的下标。

(1)使用setInterval

var a = [],     i = 0;
var interval = setInterval(function() {
i < 100 ? a.push(i++) : clearInterval(interval);
}, 0);


(2)使用数组

var a = Array(100).join(",").split(",").map(
function(item, index) {
  return index;
}
);
先是创建一个数组,然后,通过join方法把它转成字符串,然后,再通过split方法把字符串转成数组,这时候,它就拥有100个值为空的元素了,然后,再通过map函数,改变这些元素的值即可。


(3)es6方法

var arrNew = Array.from({length: 100},(v,k)=>k);
console.log(arrNew );


var arr = new Array(100).keys();
console.log(Array.from(arr));


错误方法:

var a = new Array(100);
a = a.map(function(item, index) {     return index; });

因为JavaScript数组是稀疏数组,比如,通过new Array(100)创建一个新的数组的,虽然他的长度是100,但是实际上他是一个空数组,也就是说没有真实存在的元素。所以使用map方法,根本不会去遍历这个数组100次的。




实现数组乱序

var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],     sign = 1;  a.sort(function(a, b) {
//因为Math.random产生的数在0-1之间
//所以0.5两边的概率是相等的
//大于0.5时为升序,小于0.5时为降序
sign = (Math.random() > 0.5) ? 1 : -1;
return (a - b) * sign;   });




有一个长度为100的数组,请以优雅的方式求出该数组的前10个元素之和

分析:其实,对于数组求和有很多种方法,也很简单。但是,这题有两个限制条件:优雅的方式、前10个元素。对于“前10个元素”这个限制条件可以使用Array.prototype.slice()方法来截取,对于”优雅的方式”,我的理解是应该尽可能使用数组自带的方法,最好可以使用高阶函数!所以我觉得应该是Array.prototype.reduce()方法。

var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], sum = 0;
sum = a.slice(0, 10).reduce(function(pre, current)  {
 return pre + current; });   console.log(sum); //55


注意, Array的reduce()把一个函数作用在这个Array的[x1, x2, x3…]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算



var User = {     count: 1,
getCount: function() {     return this.count;   }
};
console.log(User.getCount());  //输出1
var func = User.getCount;
console.log(func());   //输出Undefined


这里func的上下文是window,因此已经失去了count属性。改进如下,使用Function.prototype.bind

var func = User.getCount.bind(User);
console.log(func());


十一

解析URL地址

这里的方法就在JS代码里先创建一个a标签然后将需要解析的URL赋值给a的href属性

function parseURL(url) {
var a =  document.createElement('a');
a.href = url;
return {
source: url,
protocol: a.protocol.replace(':',''),
host: a.hostname,
port: a.port,
query: a.search,
params: (function(){
var ret = {},
seg = a.search.replace(/^\?/,'').split('&'),
len = seg.length, i = 0, s;
for (;i<len;i++) {
if (!seg[i])
{ continue; }
s = seg[i].split('=');
ret[s[0]] = s[1];
}
return ret;
})(),
file: (a.pathname.match(/\/([^\/?#]+)$/i) || [,''])[1],
hash: a.hash.replace('#',''),
path: a.pathname.replace(/^([^\/])/,'/$1'),
relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [,''])[1],
segments: a.pathname.replace(/^\//,'').split('/')
};
}


用法

var myURL = parseURL('http://abc.com:8080/dir/index.html?id=255&m=hello#top');

myURL.file;     // = 'index.html'
myURL.hash;     // = 'top'
myURL.host;     // = 'abc.com'
myURL.query;    // = '?id=255&m=hello'
myURL.params;   // = Object = { id: 255, m: hello }
myURL.path;     // = '/dir/index.html'
myURL.segments; // = Array = ['dir', 'index.html']
myURL.port;     // = '8080'
myURL.protocol; // = 'http'
myURL.source;   // = 'http://abc.com:8080/dir/index.html?id=255&m=hello#top'


十二

重构如下两栏布局



<div class="content"><div class="aside"></div><div class="main"></div></div>


/*Qzone版*/
.aside{float:left;width:170px;}
.main{float:left;width:790px;}
/*朋友网版*/
.aside{float:left;width:170px;}
.main{overflow:hidden;#zoom:1;}
/*Facebook版*/
.aside{float:left;width:170px;}
.main{margin-left:170px;zoom:1;}
/*Yahoo版*/
.content{position:relative;zoom:1;}
.aside{position:absolute;left:0;top:0;width:170px;}
.main{margin-left:170px;zoom:1;}
/*Google版*/
.aside{display:inline-block;width:170px;}
.main{display:inline-block;width:790px;}


Qzone、朋友网、Facebook都给左栏浮动,唯一不同的是右栏的写法,Qzone给右栏定宽并且浮动,而朋友网和Facebook则并没有给右栏定宽也未浮动,而是利用了创建BFC并且为低版本IE触发hasLayout的原理让右栏自适应宽度。

Yahoo和Google两栏都未用浮动,唯一不同的是Yahoo用了绝对定位的方法,而谷歌用了inline-block,Google已经宣布旗下一些产品放弃对IE8 的支持,所以Google可以大胆的使用inline-block去实现布局,不用去为其他低版本浏览器写一大堆的hack。

十三

常见邮箱验证

输入的数据必须包含 @ 符号和点号(.)。同时,@ 不可以是邮件地址的首字符,并且 @ 之后需有至少一个点号

function validateForm(){
var x=document.forms["myForm"]["email"].value;
var atpos=x.indexOf("@");
var dotpos=x.lastIndexOf(".");
if (atpos<1 || dotpos<atpos+2 || dotpos+2>=x.length){
alert("不是一个有效的 e-mail 地址");
return false;
}
}


?????????讲一下css的动画(我不太了解, 就直说不太了解,然后她让我试着写了下,就写了些印象里的,她说差不多)

猜一下,如果要绑定动画的话,在哪里绑定?怎么绑定?

如果是行内元素呢?如果字体font-size是10px,行高line-height是2px,显示多高?(依然不知道,猜测是2px,剩余的部分会被隐藏掉)。刚才试了下,发现打错了:

十四

找出整型数组中乘积最大的三个数

var unsorted_array = [-10, 7, 29, 30, 5, -10, -70];

computeProduct(unsorted_array); // 21000

function sortIntegers(a, b) {
return a - b;
}

// greatest product is either (min1 * min2 * max1 || max1 * max2 * max3)
function computeProduct(unsorted) {
var sorted_array = unsorted.sort(sortIntegers),
product1 = 1,
product2 = 1,
array_n_element = sorted_array.length - 1;

// Get the product of three largest integers in sorted array
for (var x = array_n_element; x > array_n_element - 3; x--) {
product1 = product1 * sorted_array[x];
}
product2 = sorted_array[0] * sorted_array[1] * sorted_array[array_n_element];

if (product1 > product2) return product1;

return product2
};


十五

给定两个数组,要求求出两个数组的交集,注意,交集中的元素应该是唯一的。

var firstArray = [2, 2, 4, 1];
var secondArray = [1, 2, 0, 2];

intersection(firstArray, secondArray); // [2, 1]

function intersection(firstArray, secondArray) {
var hashmap = {};
var intersectionArray = [];

firstArray.forEach(function(element) {
hashmap[element] = 1;
});

secondArray.forEach(function(element) {
if (hashmap[element] === 1) {
intersectionArray.push(element);
hashmap[element]++;
}
});

return intersectionArray;
}


十六

给定两个字符串,判断是否颠倒字母而成的字符串,譬如Mary与Army就是同字母而顺序颠倒:

var firstWord = "Mary";
var secondWord = "Army";

isAnagram(firstWord, secondWord); // true

function isAnagram(first, second) {
// For case insensitivity, change both words to lowercase.
var a = first.toLowerCase();
var b = second.toLowerCase();

// Sort the strings, and join the resulting array to a string. Compare the results
a = a.split("").sort().join("");
b = b.split("").sort().join("");

return a === b;
}


十七

判断某个字符串是否为回文字符串,譬如racecar与race car都是回文字符串:

function isPalindrome(word) {
// Replace all non-letter chars with "" and change to lowercase
var lettersOnly = word.toLowerCase().replace(/\s/g, "");

// Compare the string with the reversed version of the string
return lettersOnly === lettersOnly.split("").reverse().join("");
}


十八

判断是否为 2 的指数值

// For the non-zero case:
function isPowerOfTwo(number) {
return number & (number - 1) === 0;
}

// For zero-case:
function isPowerOfTwoZeroCase(number) {
return (number !== 0) && ((number & (number - 1)) === 0);
}


十九

二进制转换

function decimalToBinary(digit) {
if(digit >= 1) {
if (digit % 2) {
return decimalToBinary((digit - 1) / 2) + 1;
} else {
// Recursively return proceeding binary digits
return decimalToBinary(digit / 2) + 0;
}
} else {
// Exit condition
return '';
}
}


二十

创建一个函数来判断给定的表达式中的大括号是否闭合:

var expression = "{{}}{}{}"
var expressionFalse = "{}{{}";

isBalanced(expression); // true
isBalanced(expressionFalse); // false
isBalanced(""); // true

function isBalanced(expression) {
var checkString = expression;
var stack = [];

// If empty, parentheses are technically balanced
if (checkString.length <= 0) return true;

for (var i = 0; i < checkString.length; i++) {
if(checkString[i] === '{') {
stack.push(checkString[i]);
} else if (checkString[i] === '}') {
// Pop on an empty array is undefined
if (stack.length > 0) {
stack.pop();
} else {
return false;
}
}
}

// If the array is not empty, it is not balanced
if (stack.pop()) return false;
return true;
}


二十一

二分搜索

(1)首先,从有序数组的中间的元素开始搜索,如果该元素正好是目标元素(即要查找的元素),则搜索过程结束,否则进行下一步。

(2)如果目标元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半区域查找,然后重复第一步的操作。

(3)如果某一步数组为空,则表示找不到目标元素。

// 非递归算法
function binary_search(arr, key) {
var low = 0,
high = arr.length - 1;
while(low <= high){
var mid = parseInt((high + low) / 2);
if(key == arr[mid]){
return  mid;
}else if(key > arr[mid]){
low = mid + 1;
}else{
high = mid -1;
}
}
return -1;
};
var arr = [1,2,3,4,5,6,7,8,9,10,11,23,44,86];
var result = binary_search(arr,10);
alert(result); // 9 返回目标元素的索引值


// 递归算法
function binary_search(arr,low, high, key) {
if (low > high){
return -1;
}
var mid = parseInt((high + low) / 2);
if(arr[mid] == key){
return mid;
}else if (arr[mid] > key){
high = mid - 1;
return binary_search(arr, low, high, key);
}else if (arr[mid] < key){
low = mid + 1;
return binary_search(arr, low, high, key);
}
};
var arr = [1,2,3,4,5,6,7,8,9,10,11,23,44,86];
var result = binary_search(arr, 0, 13, 10);
alert(result); // 9 返回目标元素的索引值


二十二

手写数组快速排序

“快速排序”的思想很简单,整个排序过程只需要三步:

(1)在数据集之中,选择一个元素作为”基准”(pivot)。

(2)所有小于”基准”的元素,都移到”基准”的左边;所有大于”基准”的元素,都移到”基准”的右边。

(3)对”基准”左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。

var quickSort = function(arr) {
  if (arr.length <= 1) { return arr; }
  var pivotIndex = Math.floor(arr.length / 2);
  var pivot = arr.splice(pivotIndex, 1)[0];
  //这里注意splice返回,是一个包含被删除项目的新数组,所以执行后arr已经删除元素,而【0】则代表被删除的pivot
  var left = [];
  var right = [];
  for (var i = 0; i < arr.length; i++){
    if (arr[i] < pivot) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }
  return quickSort(left).concat([pivot], quickSort(right));
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  前端 面试