近来预备低级前端口试,发现有许多手写完成什么的,比方什么手写完成bind,promise。手写ajax,手写一些算法。
翻阅了许多书本和博客。
这里做一个总结革新,算是对我背面也许为期一个月找工作的预备。
手写完成bind()
Function.prototype._bind = function (context) {
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fBind = function () {
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(this instanceof fBind ? this : context, args.concat(bindArgs));
}
fBind.prototype = self.prototype&&Object.create(self.prototype)
return fBind;
}
简朴的申明:
- 这里之所以传参的时刻须要两个数组,是因为斟酌到用
new
以组织函数的情势挪用硬绑定函数的状况:this
这时候是应当指向实例对象的。 - 这模样就须要继续之前函数的要领,
fBind.prototype = self.prototype&&Object.create(self.prototype)
,同时也能够用 Object.setPrototypeOf(fBind.prototype,self.prototype)
。
斟酌到存在undefined
的状况,前面加一个推断self.prototype&&.....
- 关于
apply
的第一个参数,假如斟酌到之前的状况,是不能传入context
的,这须要做一个推断。
像是下面的状况
function Foo(price){
this.price =price
this.fn = ()=>{
console.log('hi fn')
}
console.log(this.name)
}
Foo.prototype.sayMyName = function(){
console.log(this.name)
}
var Obj1 = {
name:'obj1'
}
var b =Foo._bind(Obj1)
b() //"obj1"
var c = new b(1000)//"i am c"
c.name = 'i am c'
c.sayMyName()
这里的this
的指向就是c
,它指向实例对象自身。
背面以这道题为引线口试官可能会诘问:
- 什么是实行上下文
- this的推断
- call,bind的区分
手写一个函数完成斐波那契数列
起首拷一个阮神在他es6教程里的一个写法。
function* fibonacci() {
let [prev, curr] = [0, 1];
for (;;) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
for (let n of fibonacci()) {
if (n > 1000) break;
console.log(n);
}
更精简的
const feibo= max=>{
let [a,b,i]= [0,1,1]
while(i++<=max) {
[a,b] = [b,a + b ]
console.log(b)
}
return a
}
相对是异常简朴的,以为也不会多问啥,就不多说了。
手写一个简朴的ajax
let xhr = new XMLHttpRequest()
xhr.open('get', url, true)
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
console.log('请求完成')
if(this.status >= 200 &&this.status<300){
conso.log('胜利')
}else{
consol.log('失利')
}
}
}
xhr.onerror = function(e) {
console.log('衔接失利')
}
xhr.send()
也许是这么个意义就差不多了,顺势可能会问一些状况码和状况值的题目,或许直接问到关于http上面的题目。
原型继续
function inherit(supertype,subtype){
Object.setPrototypeOf(subtype.prototype,supertype.prototype)
subtype.prototype.constructor = subtype
}
function Car(name,power){
this.name=name
this.power = power
}
Car.prototype.showPower = function(){
console.log(this.power)
}
function Changan(price,name,power){
this.price = price
Car.call(this,name,power)
}
inherit(Car,Changan)
Changan.prototype.showName = function(){
console.log(this.name)
}
var star = new Changan(100000,'star',500)
star.showPower()
防抖与撙节
function debounce(fn,duration){
var timer
window.clearTimeout(timer)
timer = setTimeout(()=>{
fn.call(this)
},duration)
}
function throttle(fn,duration){
let canIRun
if(!canIRun)return
fn.call(this)
canIRun = false
setTimeout(()=>{
canIRun = true
},duration)
}
数组去重
我平常就用这两种,大部分状况都能敷衍了。
[...new Set(array)]
//hash
function unique(array) {
const object = {}
array.map(number=>{
object[number] = true
})
return Object.keys(object).map(//.......)
}//也许是如许的意义,写法依据数组的差别可能会有所转变
深拷贝
应当是口试内里手写xxx涌现频次最高的题了,无论是笔试照样口试。
老是让你手写完成深拷贝函数。
事实上,js并不能做到真正完整的规范的深拷贝
所以不论你写什么样的深拷贝函数都邑有不实用的处所,这取决于运用的场景和拷贝的对象,假如口试官在这上面研讨比较深的话,是很难做到圆满的。
既然如许就写个迁就一点的深拷贝吧,面向口试的那种。
function deepClone(item) {
return result;
}
起首在范例推断上做一个挑选,平常状况来讲,用
new
建立的实例对象用typeof
推断会出题目的,相比之下instanceof
也不靠谱。这内里相对比较靠谱的Object.prototype.toString.call(item)
。(这个实在也不兼容到悉数状况和机能请求,然则面向口试代码可读性会高一点)。type = Object.prototype.toString.call(item).slice(8,this.length-1), //[object String],[object Array],[object Object]
- 函数的拷贝,这里不能运用
bind
,会转变this
指向或影响后续运用call
挪用该拷贝的函数,大部分状况是不必要的,这里就直接赋值吧。 因而这里能够把基础数据范例和
Function
放一同。fk= ['String','Number','Boolean','Function'].indexOf(type)>-1
-
dom
对象的拷贝:result = item.cloneNode(true);
- 疏忽正则
Date
,[object Object]
,[object Array]
放到背面的推断let other = { //须要递归或许其他的操纵 Array() { result = [] item.forEach((child, index)=>{ hash.set(item, result); result[index] = deepClone(child,hash) }) }, Date(){ result = new Date(item) }, Object(){ result = {} Reflect.ownKeys(item).forEach(child=>{ hash.set(item, result); result[child] = deepClone(item[child],hash) }) } } other[type]()
这模样是不是是相对清楚一些了,敷衍平常的状况应当差不多了,然则没斟酌轮回援用。
这里给个思绪是运用ES6
的WeakMap
,不知道的兄弟能够看看阮神的ES6博客,为防备爆栈,我把轮回援用直接扔给它,圆满拷贝。
就相当于
var wm = new WeakMap()
var obj = {
name:null
}
obj.name = obj
wm.set(obj,wm.get(obj))
console.log(wm)
如今就须要在开首搜检一下轮回援用,然后直接返回WeakMap对象键名为item参数对象的值
所以终究代码就是
function deepClone(item,hash = new WeakMap()) {
if (!item) return item
if (hash.has(item))return hash.get(item); //搜检轮回援用
var result,
type = Object.prototype.toString.call(item).slice(8,this.length-1),
fk= ['String','Number','Boolean','Function'].indexOf(type)>-1
if(fk){
result = item;//直接赋值
}else if(item.nodeType && typeof item.cloneNode === "function"){
result = item.cloneNode(true); //是不是是dom对象
}else{
let other = { //须要递归或许其他的操纵
Array() {
result = []
item.forEach((child, index)=>{
hash.set(item, result);
result[index] = deepClone(child,hash)
})
},
Date(){
result = new Date(item)
},
Object(){
result = {}
Reflect.ownKeys(item).forEach(child=>{
hash.set(item, result);
result[child] = deepClone(item[child],hash)
})
}
}
other[type]()
}
return result;
}
意义就也许是这个意义,固然深拷贝的要领有许多,以至不一定用到递归。口试官总会有找茬的处所的。
我以为我写的这个照样满足我如今找工作的级别请求的。
然后是我用来测试的对象
var obj1 = {
name:'obj1',
one : {
a:new Date(),
b:new String('1-2'),
c:new Array(['this','is',1,{a:23}]),
d: function () {
if(true){
return 'd'
}
},
e:new Number(15),
f:new Boolean(true)
},
two(x){
console.log(x+' '+this.name)
},
three : [
{
a:'this is a',
b:document.body,
c:{
a:[1,2,3,4,5,[13,[3],true],10],
b:{
a:{
a:[1,2,3]
},
b:2
}
}
},
],
four:[1,2]
}
obj1.name=obj1
obj1.four[3] = obj1
var copy = deepClone(obj1)
console.log(copy)
copy.two.call(window,'hi')
## new
简朴说下也许是这么一个历程
- 建立一个空对象
- 实行传入的组织函数,实行历程当中对 this 操纵就是对 这个空对象 举行操纵。
- 返回这个空对象
模仿须要斟酌的题目
- 是一个空对象,这内里的写法
obj
原型链是没有上一级的,即不存在与其他任何对象之间的联络,虽然在这内里没多少区分:var obj = Object.create(null),
-
this
指向这个空对象:let rt = Constructor.apply(obj, arguments);
- 能够接见组织函数的原型链,
Object.setPrototypeOf(obj, Constructor.prototype);
- 假如组织函数有返回值,并且是一个对象,那末实例对象拿到的就是这个对象(应当只是值,并非援用)。所以这里要做个推断
return typeof rt === 'object' ? rt : obj;
终究的代码
function _new(){
var obj = Object.create(null),
Constructor = [].shift.call(arguments);
Object.setPrototypeOf(obj, Constructor.prototype);
let rt = Constructor.apply(obj, arguments);
return rt instanceof Object ? rt : obj;
}
<br/>
<br/>
疾速排序
快排
:代码精简了一点
function quickSort(arr){
if(arr.length<=1)return arr
var index = Math.floor(arr.length/2),
number = arr.splice(index,1)[0],
left = [],
right = [];
arr.forEach(item=>{
item<=number?left.push(item):right.push(item)
})
return quickSort(left).concat([number],quickSort(right))
}
这时期会不断更新并修正,这内里的手写完成您假如有更好的写法或许新的思绪,也愿望能够申明交换。末了感谢大佬些的寓目。