【2020面试精选】 手写JavaScript常见API
一 请用ES5实现const功能
分析:
const与其他定义变量的方式不同点在于,const定义的基本类型,其值不可更改,const定义的引用类型,指向堆内存的地址不能更改(注意:此处说的是内存地址不变,而不是内存地址指向的内存空间里所存储的数据不变)
思路:
要想实现变量的值不被重写,如果我们能监听到变量赋值操作,我们就可以阻止变量赋值,进而就可以实现赋值拦截。问题转化成监听赋值操作,首先想到的便是Object.defineProperty()方法,它可以定义对象属性的基础属性,包括取值赋值。但是这里有一个问题:这个方法是针对对象的,那全局变量怎么办?这里要注意的是:全局变量实际上是全局对象window的属性。
可复制代码:
// ES5实现const
function _const (obj, key, value) {
Object.defineProperty(obj, key, {
configurable: false, // 可配置性
get: function() {
return value
},
set: function(data) {
if(value !== data) {
throw new TypeError('Assignment to constant variable')
} else {
return data
}
}
})
}
二 请用ES5实现call
分析:
call的主要作用是改变函数中this指向并调用函数,函数入参为枚举型,并且,改变this指向后并不返回新的函数。基于这些特点,可做如下实现:(如果没有接触过,很难想到会这么写)
可复制代码:
// call
Function.prototype.myCall = function(context = window, ...args) {
const key = Symbol('新增的独一无二的属性,防止覆盖原有属性') // 新建一个属性key
context[key] = this // 新增的属性的值赋值为this
const res = context[key](...args) // 通过隐式绑定的方式调用函数
delete context[key] // 删除新增的key
return res //返回函数调用的返回值
}
三 请用ES5实现apply
分析:
apply的主要作用是改变函数中this指向并调用函数,函数入参为类数组,并且,改变this指向后并不返回新的函数。基于这些特点,可做如下实现:(写法基本同call,只是入参形式变了)
可复制代码:
// apply
Function.prototype.myApply = function(context = window, args) {
const key = Symbol('建立一个独一无二的属性,防止覆盖原有属性') // 新建一个属性key
context[key] = this // 新增的属性赋值为this
const res = context[key](...args) // 将传入的参数数组展开调用
delete context[key]
return res //返回函数调用的返回值
}
四 请用ES5实现bind
分析:
bind的特点是,只是改变函数this指向,并不调用函数,并且最终返回的是一个新的函数,基于此可做如下实现:
可复制代码:
// bind
Function.prototype.myBind = function(context, ...fArg) {
const fn = this
fArg = fArg || []
return function newFn(...newFnArgs) {
if(this instanceof newFn) {
return new fn(...args, ...newFnArgs)
}
return fn.apply(context, [...fArg, ...newFnArgs])
}
}
五 请输出1-1000内所有的质数
分析:
质数指的是只能被1和本身除尽,并且没有其他约数的自然数。
可复制代码:
// 判断质数
function isPrime(n) {
if(n<=3 && n > 1) { return n }
if (n % 2 == 0 || n % 3 == 0) { return false; }
for (var i = 5; i * i <= n; i += 6) {
if (n % i == 0 || n % (i + 2 == 0)) { return false; }
}
return n;
}
// 输出1-1000质数
var res = []
for(let i=2;i<1000;i++) {
if(isPrime(i)) {
res.push(isPrime(i))
}
}
console.log(res)
文末
今日分的手写就总结到这,虽然不多,但够经典。一日一钱,千日千钱,绳锯木断,水滴石穿。