正值金九银十的招聘旺季,我把我珍藏整理多年的前端面试题分享给你们,分三部分。这是第二部分,js相关的颇有用的基础知识。javascript
实现一个LazyMan,能够按照如下方式调用:
LazyMan(“Hank”)输出:
Hi! This is Hank!
LazyMan(“Hank”).sleep(10).eat(“dinner”)输出
Hi! This is Hank!
//等待10秒..
Wake up after 10
Eat dinner~
LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输出
Hi This is Hank!
Eat dinner~
Eat supper~
LazyMan(“Hank”).sleepFirst(5).eat(“supper”)输出
//等待5秒
Wake up after 5
Hi This is Hank!
Eat supper
以此类推。
复制代码
这是典型的JavaScript流程控制,问题的关键是如何实现任务的顺序执行。在Express有一个相似的东西叫中间件,这个中间件和咱们这里的吃饭、睡觉等任务很相似,每个中间件执行完成后会调用next()函数,这个函数用来调用下一个中间件。css
对于这个问题,咱们也能够利用类似的思路来解决,首先建立一个任务队列,而后利用next()函数来控制任务的顺序执行:html
function _LazyMan(name){
this.tasks=[];
var self=this;
var fn=(function(n){
var name=n;
return function(){
console.log("Hi! this is "+name+"!");
self.next();
}
})(name);
this.tasks.push(fn);
setTimeout(function(){
self.next();
},0); // 在下一个事件循环启动任务
}
/* 事件调度函数 */
_LazyMan.prototype.next=function(){
var fn=this.tasks.shift();
fn && fn();
}
_LazyMan.prototype.eat=function(name){
var self=this;
var fn=(function(name){
return function(){
console.log("Eat "+name+" ~");
self.next()
}
})(name);
this.tasks.push(fn);
return this; // 实现链式调用
}
_LazyMan.prototype.sleep=function(time){
var self=this;
var fn=(function(time){
return function(){
setTimeout(function(){
console.log("Wake up after "+time+" s!");
self.next();
},time*1000);
}
})(time);
this.tasks.push(fn);
return this;
}
_LazyMan.prototype.sleepFirst=function(time){
var self=this;
var fn=(function(time){
return function(){
setTimeout(function(){
console.log("Wake up after "+time+" s!");
},time*1000);
}
})(time);
this.tasks.unshift(fn);
return this;
}
/* 封装 */
function LazyMan(name){
return new _LazyMan(name);
}
复制代码
lazyman里边含有链式调用,那么每个子任务 return this;这个程序支持任务优先顺序,那么就须要两个贯穿全场的Promise对象:第一,普通顺序promise;第二,插入顺序promise,同时插入顺序是阻塞普通顺序的,代码以下:前端
function _LazyMan(name){
this.orderPromise=this.newPromise(); // 定义顺序promise对象
this.insertPromise=this.newPromise(); // 定义插入promise对象
this.order(function(resolve){
console.log(name);
resolve();
})
}
_LazyMan.prototype={
/*实例化promise对象工厂*/
newPromise:function(){
return new Promise(function(resolve,reject){
resolve();
})
},
order:function(fn){
var self=this;
this.orderPromise=this.orderPromise.then(function(){
return new Promise(function(resolve,reject){
//若是有insertPromise,阻塞orderPromise.
self.fir?self.insertPromise.then(function(){
fn(resolve)
}):fn(resolve)
})
})
},
insert:function(fn){
var self=this;
this.fir=true;
this.insertPromise=this.insertPromise.then(function(){
return new Promise(function(resolve,reject){
fn(resolve);
self.fir=false;
})
})
},
sleepFirst:function(time){
this.insert(function(resolve){
setTimeout(function(){
console.log('wait '+time+' s,other logic');
resolve();
},time*1000)
})
return this;
},
eat:function(something){
this.order(function(resolve){
console.log(something+' ~~');
resolve();
})
return this;
},
sleep:function(time){
this.order(function(resolve){
setTimeout(function(){
console.log('sleep '+time+' s');
},time*1000);
})
return this;
}
}
//接口封装。
function LazyMan(name) {
return new _LazyMan(name);
}
//调用测试
LazyMan(‘RoryWu‘).firstTime(1).sleep(2).firstTime(3).eat(‘dinner‘).eat(‘breakfast‘);
// 弹出:
// wait 1 s, other logic
// wait 3 s, other logic
// RoryWu
// sleep 2 s
// dinner~~
// breakfast~~
复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.button {
height: 2em;
border: 0;
border-radius: .2em;
background-color: #34538b;
color: #fff;
font-size: 12px;
font-weight: bold;
}
</style>
</head>
<body>
<input type="button" id="button" class="button" value="点击我,显示背景色" />
<script>
document.getElementById("button").onclick = function() {
var oStyle =window.getComputedStyle(this, null); // null不是必须
// 若是考虑IE var oStyle = this.currentStyle? this.currentStyle : window.getComputedStyle(this, null);
alert(oStyle.getPropertyValue("background-color")); //这里也能够用键值获取,建议用getPropertyValue("background-color")
};
</script>
</body>
</html>
复制代码
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 0);
console.log(i);
}
复制代码
结果是:0 1 2 3 3 3 不少公司面试都爱出这道题,此题考察的知识点仍是蛮多的。 为了防止初学者栽在此问题上,此文稍微分析一下。 都考察了那些知识点呢? 异步、做用域、闭包,你没听错,是闭包。 咱们来简化此题:html5
setTimeout(function() {
console.log(1);
}, 0);
console.log(2);
复制代码
先打印2,后打印1。 由于是setTimeout是异步的。 正确的理解setTimeout的方式(注册事件): 有两个参数,第一个参数是函数,第二参数是时间值。 调用setTimeout时,把函数参数,放到事件队列中。等主程序运行完,再调用。 没啥很差理解的。就像咱们给按钮绑定事件同样:java
btn.onclick = function() {
alert(1);
};
复制代码
这么写完,会弹出1吗。不会!!只是绑定事件而已! 必须等咱们去触发事件,好比去点击这个按钮,才会弹出1。 setTimeout也是这样的!只是绑定事件,等主程序运行完毕后,再去调用。 setTimeout的时间值是怎么回事呢? 好比:jquery
setTimeout(fn, 2000)
复制代码
咱们能够理解为2000以后,再放入事件队列中,若是此时队列为空,那么就直接调用fn。若是前面还有其余的事件,那就等待。 所以setTimeout是一个约会历来都不许时的童鞋。 继续看:git
setTimeout(function() {
console.log(i);
}, 0);
var i = 1;
复制代码
程序会不会报错? 不会!并且还会准确得打印1。 为何? 由于真正去执行console.log(i)这句代码时,var i = 1已经执行完毕了! 因此咱们进行dom操做。能够先绑定事件,而后再去写其余逻辑。程序员
window.onload = function() {
fn();
}
var fn = function() {
alert('hello')
};
复制代码
这么写,彻底是能够的。由于异步!es6
es5中是没有块级做用域的
for (var i = 0; i < 3; i++) {}
console.log(i);
复制代码
也就说i能够在for循环体外访问到。因此是没有块级做用域。 但此问题在es6里终结了,由于es6,发明了let。 这回咱们再来看看原题。 原题使用了for循环。循环的本质是干吗的? 是为了方便咱们程序员,少写重复代码。 让咱们倒退50年,原题等价于:
var i = 0;
setTimeout(function() {
console.log(i);
}, 0);
console.log(i);
i++;
setTimeout(function() {
console.log(i);
}, 0);
console.log(i);
i++;
setTimeout(function() {
console.log(i);
}, 0);
console.log(i);
i++;
复制代码
由于setTimeout是注册事件。根据前面的讨论,能够都放在后面。 原题又等价于以下的写法:
var i = 0;
console.log(i);
i++;
console.log(i);
i++;
console.log(i);
i++;
setTimeout(function() {
console.log(i);
}, 0);
setTimeout(function() {
console.log(i);
}, 0);
setTimeout(function() {
console.log(i);
}, 0);
复制代码
这回你明白了为啥结果是0 1 2 3 3 3了吧。
那个,说它是闭包,又是怎么回事? 为了很好的说明白这个事情,咱们把它放到一个函数中:
var fn = function() {
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 0);
console.log(i);
}
};
fn();
复制代码
上面的函数跟咱们常见另外一个例子(div绑定事件)有什么区别:
var fn = function() {
var divs = document.querySelectorAll('div');
for (var i = 0; i < 3; i++) {
divs[i].onclick = function() {
alert(i);
};
}
};
fn();
复制代码
点击每一个div都会弹出3。道理是同样的。由于alert(i)中的i是fn做用越中的,于是这是闭包。 《javascript忍者秘籍》书里把一个函数能调用全局变量,也称闭包。 由于做者认为全局环境也能够想象成一个大的顶级函数。 怎么保证能弹出0,1, 2呢。 解决之道:以毒攻毒! 再建立个闭包!!
var fn = function() {
var divs = document.querySelectorAll('div');
for (var i = 0; i < 3; i++) {
divs[i].onclick = (function(i) {
return function() {
alert(i);
};
})(i);
}
};
fn();
复制代码
或者以下的写法:
var fn = function() {
var divs = document.querySelectorAll('div');
for (var i = 0; i < 3; i++) {
(function(i) {
divs[i].onclick = function() {
alert(i);
};
})(i);
}
};
fn();
复制代码
所以原题若是也想setTimeout也弹出0,1,2的话,改为以下:
for (var i = 0; i < 3; i++) {
setTimeout((function(i) {
return function() {
console.log(i);
};
})(i), 0);
console.log(i);
}
复制代码
想了解更多关于setTimeout(fn,0),能够参考setTimeout(fn,0)
先看题目: 请用js实现一个类P,包含成员变量a,成员变量b,成员函数sum,sum输出a与b的和,a,b默认值都为0。实现一个类M,M继承自P,在P的基础上增长成员变量c,成员函数sum变成输出a,b,c的和。
题目分析 Js全部的函数都有一个prototype属性,这个属性引用了一个对象,即原型对象,也简称原型。这个函数包括构造函数和普通函数,咱们讲的更可能是构造函数的原型,可是也不可否定普通函数也有原型,实现继承的方法不少,这里使用原型链和构造继承,即组合继承的方式。
function P(a,b){
this.a=a||0;
this.b=b||0;
this.sum=function(){
return this.a+this.b;
}
}
function M(a,b,c){
P.call(this,a,b)
this.c=c;
this.sum=function(){
return this.a+this.b+this.c;
}
}
M.prototype=new P();
var m=new M(2,2,2);
m.sum() //输出6
复制代码
接下来,咱们深刻js继承,看看js实现继承几种方式的特色。
既然要实现继承,那么首先咱们得有一个父类,代码以下:
// 定义一个动物类
function Animal (name,eye,skin) {
// 属性
this.name = name || 'Animal';
this.eye=eye;
this.skin=skin;
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
复制代码
下面给你们列出几种继承方式的实现
实现父类代码在(4.2 js继承的实现方式中) 核心: 将父类的实例做为子类的原型
function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
复制代码
特色:
缺点:
推荐指数:★★(三、4两大体命缺陷)
**核心:**使用父类的构造函数来加强子类实例,等因而复制父类的实例属性给子类(没用到原型)
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
复制代码
特色:
缺点:
推荐指数:★★(缺点3)
**核心:**为父类实例添加新特性,做为子类实例返回
function Cat(name){
var instance = new Animal();
instance.name = name || 'Tom';
return instance;
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
复制代码
特色:
缺点:
推荐指数:★★
function Cat(name){
var animal = new Animal();
for(var p in animal){
Cat.prototype[p] = animal[p];
}
Cat.prototype.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
复制代码
特色:
缺点:
推荐指数:★(缺点1)
**核心:**经过调用父类构造,继承父类的属性并保留传参的优势,而后经过将父类实例做为子类原型,实现函数复用
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
复制代码
特色:
缺点:
推荐指数:★★★★(仅仅多消耗了一点内存)
**核心:**经过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
(function(){
// 建立一个没有实例方法的类
var Super = function(){};
Super.prototype = Animal.prototype;
//将实例做为子类的原型
Cat.prototype = new Super();
})();
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
复制代码
特色:
缺点:
推荐指数:★★★★(实现复杂,扣掉一颗星)
示例:
function Animal (name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
//实例引用属性
this.features = [];
}
function Cat(name){
}
Cat.prototype = new Animal();
var tom = new Cat('Tom');
var kissy = new Cat('Kissy');
console.log(tom.name); // "Animal"
console.log(kissy.name); // "Animal"
console.log(tom.features); // []
console.log(kissy.features); // []
tom.name = 'Tom-New Name';
tom.features.push('eat');
//针对父类实例值类型成员的更改,不影响
console.log(tom.name); // "Tom-New Name"
console.log(kissy.name); // "Animal"
//针对父类实例引用类型成员的更改,会经过影响其余子类实例
console.log(tom.features); // ['eat']
console.log(kissy.features); // ['eat']
缘由分析:
关键点:属性查找过程
执行tom.features.push,首先找tom对象的实例属性(找不到),
那么去原型对象中找,也就是Animal的实例。发现有,那么就直接在这个对象的
features属性中插入值。
在console.log(kissy.features); 的时候。同上,kissy实例上没有,那么去原型上找。
恰好原型上有,就直接返回,可是注意,这个原型对象中features属性值已经变化了。
复制代码
其实这里主要是理解js值类型和引用类型
假设已经定义了父类Base对象 咱们执行以下代码
var obj = new Base();
复制代码
这样代码的结果是什么,咱们在Javascript引擎中看到的对象模型是:
var obj = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
复制代码
__proto__
成员指向了Base函数对象prototype成员对象注意:new的过程会执行构造函数Base() 再对空对象进行构造
推荐阅读 浏览器同源政策及其规避方法
栈:原始数据类型(Undefined,Null,Boolean,Number、String)
堆:引用数据类型(对象、数组和函数)
两种类型的区别是:存储位置不一样;
原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,因此放入栈中存储;
引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定,若是存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其
在栈中的地址,取得地址后从堆中得到实体
复制代码
// event(事件)工具集,来源:github.com/markyun
markyun.Event = {
// 页面加载完成后
readyEvent : function(fn) {
if (fn==null) {
fn=document;
}
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = fn;
} else {
window.onload = function() {
oldonload();
fn();
};
}
},
// 视能力分别使用dom0||dom2||IE方式 来绑定事件
// 参数: 操做的元素,事件名称 ,事件处理程序
addEvent : function(element, type, handler) {
if (element.addEventListener) {
//事件类型、须要执行的函数、是否捕捉
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent('on' + type, function() {
handler.call(element);
});
} else {
element['on' + type] = handler;
}
},
// 移除事件
removeEvent : function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.datachEvent) {
element.detachEvent('on' + type, handler);
} else {
element['on' + type] = null;
}
},
// 阻止事件 (主要是事件冒泡,由于IE不支持事件捕获)
stopPropagation : function(ev) {
if (ev.stopPropagation) {
ev.stopPropagation();
} else {
ev.cancelBubble = true;
}
},
// 取消事件的默认行为
preventDefault : function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
// 获取事件目标
getTarget : function(event) {
return event.target || event.srcElement;
},
// 获取event对象的引用,取到事件的全部信息,确保随时能使用event;
getEvent : function(e) {
var ev = e || window.event;
if (!ev) {
var c = this.getEvent.caller;
while (c) {
ev = c.arguments[0];
if (ev && Event == ev.constructor) {
break;
}
c = c.caller;
}
}
return ev;
}
};
复制代码
[1, NaN, NaN] 由于 parseInt 须要两个参数 (val, radix),
其中 radix 表示解析时用的基数。
map 传了 3 个 (element, index, array),对应的 radix 不合法致使解析失败。
复制代码
内存泄漏指任何对象在您再也不拥有或须要它以后仍然存在。
垃圾回收器按期扫描对象,并计算引用了每一个对象的其余对象的数量。若是一个对象的引用数量为 0(没有其余对象引用过该对象),或对该对象的唯一引用是循环的,那么该对象的内存便可回收。
setTimeout 的第一个参数使用字符串而非函数的话,会引起内存泄漏。
闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
复制代码
polyfill 是“在旧版浏览器上复制标准 API 的 JavaScript 补充”,能够动态地加载 JavaScript 代码或库,在不支持这些标准 API 的浏览器中模拟它们。
例如,geolocation(地理位置)polyfill 能够在 navigator 对象上添加全局的 geolocation 对象,还能添加 getCurrentPosition 函数以及“坐标”回调对象,
全部这些都是 W3C 地理位置 API 定义的对象和函数。由于 polyfill 模拟标准 API,因此可以以一种面向全部浏览器将来的方式针对这些 API 进行开发,
一旦对这些 API 的支持变成绝对大多数,则能够方便地去掉 polyfill,无需作任何额外工做。
复制代码
作的项目中,有没有用过或本身实现一些 polyfill 方案(兼容性处理方案)?
好比: html5shiv、Geolocation、Placeholder
复制代码
1. 定义 因为JavaScript容许函数有不定数目的参数,因此咱们须要一种机制,能够在函数体内部读取全部参数。这就是arguments对象的由来。
arguments对象包含了函数运行时的全部参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可使用。
var f = function(one) {
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments[2]);
}
f(1, 2, 3)
// 1
// 2
// 3
复制代码
arguments对象除了能够读取参数,还能够为参数赋值(严格模式不容许这种用法)
var f = function(a, b) {
arguments[0] = 3;
arguments[1] = 2;
return a + b;
}
f(1, 1)
// 5
复制代码
能够经过arguments对象的length属性,判断函数调用时到底带几个参数。
function f() {
return arguments.length;
}
f(1, 2, 3) // 3
f(1) // 1
f() // 0
复制代码
2. 与数组的关系 须要注意的是,虽然arguments很像数组,但它是一个对象。数组专有的方法(好比slice和forEach),不能在arguments对象上直接使用。
可是,能够经过apply方法,把arguments做为参数传进去,这样就可让arguments使用数组方法了。
// 用于apply方法
myfunction.apply(obj, arguments).
// 使用与另外一个数组合并
Array.prototype.concat.apply([1,2,3], arguments)
复制代码
要让arguments对象使用数组方法,真正的解决方法是将arguments转为真正的数组。下面是两种经常使用的转换方法:slice方法和逐一填入新数组。
var args = Array.prototype.slice.call(arguments);
// or
var args = [];
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
复制代码
3. callee属性 arguments对象带有一个callee属性,返回它所对应的原函数。
var f = function(one) {
console.log(arguments.callee === f);
}
f() // true
复制代码
能够经过arguments.callee,达到调用函数自身的目的。这个属性在严格模式里面是禁用的,所以不建议使用。
4. 题目sum(2)(3)
// 写一个 function 让下面两行代码输出的结果都为 5
console.log(sum(2, 3));
console.log(sum(2)(3));
复制代码
说实话,第一眼看到的时候内心是有点虚的(由于第一次看到它)。sum(2)(3),这种形式的代码确实少见。可是第一反应就是链式调用。 链式调用咱们熟悉啊,特别是 jQuery 里面,咱们经常能看到连着写的代码。实现原理就是在方法结束时 return 合适的元素对象。
$('#id').parent().siblings('selector').css({
color: 'red'
});
复制代码
这道题考什么呢?认真分析了一下,应该有链式调用,toString,柯里化,数组操做等相关内容。大概这些能够知足需求吧? 如何写代码,脑海中大致上有构思了,可是当时手上仅有笔和纸,思路连不上来啊。还好面前放着一台台式机(嘿嘿嘿,机器上写完再抄回纸上)
个人实现大概是这样的。
var sum = (function() {
var list = [];
var add = function() {
// 拼接数组
var args = Array.prototype.slice.call(arguments);
list = list.concat(args);
return add;
}
// 覆盖 toString 方法
add.toString = function() {
// 计算总和
var sum = list.reduce(function(pre, next) {
return pre + next;
});
// 清除记录
list.length = 0;
return sum;
}
return add;
})();
sum(2, 3);
// 5
sum(2)(3);
// 5
复制代码
这个方法比较复杂,下面介绍个简便的。
var add = function add() {
var cache;
if (arguments.length === 1) {
cache = arguments[0];
return function ( number ) {return cache + number;};
}
else return arguments[0] + arguments[1];
};
复制代码
简单的浅复制实现:
var obj={ a:1,arr:[2,3] };
var shallowObj=shallowCopy(obj);
function shallowCopy(src){
var dst = {};
for (var prop in src){
if(src.hasOwnProperty(prop)){
dst[prop]=src[prop];
}
}
return dst;
}
复制代码
由于浅复制只会将对象的各个属性进行依次复制,并不会进行递归复制,而 JavaScript 存储对象都是存地址的,因此浅复制会致使 obj.arr 和 shadowObj.arr 指向同一块内存地址,大概的示意图以下。
shadowObj.arr[1] = 5;
obj.arr[1] // = 5
复制代码
而深复制则不一样,它不只将原对象的各个属性逐个复制出去,并且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。这就不会存在上面 obj 和 shadowObj 的 arr 属性指向同一个对象的问题。
var obj = { a:1, arr: [1,2] };
var obj2 = deepCopy(obj);
复制代码
结果以下面的示意图所示:
须要注意的是,若是对象比较大,层级也比较多,深复制会带来性能上的问题。在遇到须要采用深复制的场景时,能够考虑有没有其余替代的方案。在实际的应用场景中,也是浅复制更为经常使用。
代码递归实现以下:
function deepCopy(o,c){
var c = c || {}
for(var i in o){
if(typeof o[i] == 'object'){
if(o[i].constructor===Array){
c[i]=[]
}else{
c[i]={}
}
deepCopy(o[i],c[i])
}else{
c[i]=o[i]
}
}
return c
}
复制代码
jquery 中如何将数组转化为json字符串,而后再转化回来?
$.fn.stringifyArray = function(array) {
return JSON.stringify(array)
}
$.fn.parseArray = function(array) {
return JSON.parse(array)
}
而后调用:
$("").stringifyArray(array)
复制代码
针对 jQuery 的优化方法?
*基于Class的选择性的性能相对于Id选择器开销很大,由于需遍历全部DOM元素。
*频繁操做的DOM,先缓存起来再操做。用Jquery的链式调用更好。
好比:var str=$("a").attr("href");
*for (var i = size; i < arr.length; i++) {}
for 循环每一次循环都查找了数组 (arr) 的.length 属性,在开始循环的时候设置一个变量来存储这个数字,可让循环跑得更快:
for (var i = size, length = arr.length; i < length; i++) {}
复制代码
在线电子书阅读前端常见面试题汇总
转载请注明
极客教程-极客教程