给定2个有序列表,求它们的交集
要点:有序的,可以设置2个“游标”,比较大小后,根据情况移动游标,直到遍历完为止,时间复杂度O(n)
function getJointSet (arrLeft,arrRight) {
let joint = [], leftSize = arrLeft.length, rightSize = arrRight.length;
if (leftSize === 0 || rightSize === 0) {
return []
}
let l = 0, r = 0
while ( l < leftSize && r < rightSize ) {
if ( arrLeft[l] > arrRight[r] ) {
r++;
} else if ( arrLeft[l] < arrRight[r] ) {
l++;
} else if ( arrLeft[l] === arrRight[r] ) {
joint.push(arrLeft[l])
l++;
r++;
}
console.log('没戏',arrLeft[l],arrRight[l])
}
return joint;
}
let js = getJointSet([1,2,4,5,7],[4,5,7,12,14,16,25,34])
console.log(js)
手写一个LRU(最近最少使用)算法
LRU,顾名思义,在限定长度的空间内,如果访问到一个存在的元素或者添加一个元素,则将这个元素放到队头。如果添加之前没有空间,就先弹出队尾的元素,再进行添加操作
要点:我的LRU基于双链表,熟悉双链表的基本都能实现
class Elem<E> {
value: E
next: Elem<E>
prev: Elem<E>
constructor (value: E, prev = null, next = null) {
this.value = value;
this.prev = null;
this.next = null;
}
valueOf():E {
return this.value;
}
}
interface LRUInterface<E> {
get( param: Function|E|number, matchBox:boolean ): Elem<E>|E|null
hit (elem: Elem<E>):void
add( param: E ): boolean
pop(): boolean
}
class LRU<E> implements LRUInterface<E> {
head: Elem<E>
tail: Elem<E>
size: number
limit: number
static of (iterable: ArrayLike<any>): LRU<any> {
const lru = new LRU(iterable.length);
lru.head = iterable[0] || null;
for( let i = 1; i<iterable.length; i++) {
lru.add(iterable[i])
}
return lru;
}
constructor(limit:number) {
this.head = null;
this.tail = null;
this.limit = limit;
this.size = 0;
}
get( param: Function|E|number, matchBox:boolean = false ): Elem<E>|E|null {
if (this.size < 1) {
return null;
}
let current = this.head;
let index = 0;
while (current && index < this.size ) {
const currentValue = current.valueOf();
if (typeof param === "number" && param === index) {
this.hit(current);
return currentValue;
} else if ( typeof param === 'function' && !matchBox && param.call(this,current.valueOf(),index) ) {
this.hit(current);
return currentValue;
} else if ( currentValue === param ) {
this.hit(current);
return matchBox?current:currentValue;
} else {
index += 1;
current = current.next;
}
}
return null;
}
hit (elem: Elem<E>):void {
if (elem !== this.head && this.size > 1) {
elem.prev.next = elem.next;
elem.prev = null;
const t = this.head;
t.prev = elem;
this.head = elem;
elem.next = t;
}
}
add( param: E ): boolean {
const elem = new Elem(param)
if( this.size === this.limit ){
this.pop()
}
if (this.size === 0) {
this.head = elem
this.tail = elem
} else {
let t = this.head;
this.head = elem;
t.prev = elem;
elem.next = t;
}
this.size += 1;
return true;
}
pop(): boolean {
if (this.size <= 0) {
return false;
} else if (this.size === 1) {
this.head = null;
this.tail = null;
this.size = 0
} else {
const poped = this.tail;
this.tail = this.tail.prev;
this.tail.next = null;
this.size -= 1;
}
}
}
实现一个单例模式,且不能直接调用(必须new构造)
要点:实现static
function SingleClass () {
if ( !this instanceof SingleClass ) {
thow Error('must construct with "new" operator!')
}
if (!SingleClass.instance){
SingleClass.instance = this;
}
return SingleClass.instance;
}
实现一个事件订阅/发布类
自己实现一个bind函数
要点:原生bind传参规则、call/apply运用
Function.prototype.myBind = function (context) {
var func = this
var slice = Array.prototype.slice
var restArguments = slice.call(arguments,1) //接受bind传入的载荷
var bindFunc = function () {
var afterArguments = slice.call(arguments) // 接收实例传入的载荷
return func.apply(context,restArguments.concat(afterArguments))
}
// 绑过的函数不能再绑
Object.defineProperty(bindFunc,'myBind',{
value: function (){return bindFunc},
configurable: false
})
return bindFunc
}
自己实现一个Promise
https://www.jianshu.com/p/d36f6f5f3372
用Promise函数封装XHR请求:
function httpRequest(url,userOption) {
return new Promise ((res,rej)=>{
const option = Object.assign({
method: 'GET',
headers: {},
},userOption)
const xhr = new XMLHttpRequest()
if (option.method.toUpperCase() === 'GET' && option.params) {
let queryString = /\?/.test(url)?'&':'?'
let params = option.params
for( let key of Object.keys(params) ) {
queryString += key + '=' + params[key] + '&'
}
url += queryString.substr(0,queryString.length-1)
}
// 打开
xhr.open(option.method.toUpperCase(),url,true)
// 请求头必须在打开后设置
if (option.headers) {
let headers = option.headers
for (let key of Object.keys(headers) ) {
xhr.setRequestHeader(key,headers[key])
}
}
xhr.onreadystatechange = ()=>{
if (xhr.readyState === 4 ) {
let response = {
success: false,
status: xhr.status
}
if (xhr.status ===200) {
response.success = true
response.data = xhr.responseText
res(response)
option.callback && option.callback(response)
} else {
response.errorMsg = xhr.responseText
rej(response)
option.callback && option.callback(response)
}
}
}
if(option.method.toUpperCase() ==='POST' || option.method.toUpperCase() ==='PUT' ){
xhr.send(JSON.stringify(option.params))
} else {
xhr.send()
}
})
}
Promise有什么缺点,async/await 如何解决这个问题
设想这样的场景,我想先从后端获取某个ID,再通过这个ID发起请求拿数据,即便使用Promise(以及promise化的API)一样也是回调地狱:
function getID () {
return fetch('/get_id').then(res=>res.id)
}
function getDataByID (id) {
return fetch(`/data/${id}`)
}
function gogogo () {
getID().then(id=>{
getDataByID(id).then(onData)
})
}
function onData(res) {
// do sth with res
}
gogogo()
使用async/await解决上述问题:https://www.jianshu.com/p/220b7f3469d5
手写一个webpack4.0配置,要求:
- 使用
src/js
下的index.js
作为入口,打包后输出到src
平级目录dist
下,入口文件为dist/bundle.js
- 将
src/index.html
同样输出为dist/index.html
- 抽取JavaScript中导入的的css文件,输出为
dist/style.css
- 复制
src/images
下的文件到dist/images
中 - 构建前删除上次构建过的文件
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
mode : 'production',
entry: './src/js/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}]
},
plugins: [
// 加入 html 模板任务
new HtmlWebpackPlugin({
// 模板文件
template: 'src/index.html',
// 打包后文件名称,会自动放到 output 指定的 dist 目录
filename: 'index.html'
}),
// 复制图片
new CopyWebpackPlugin([{
from : path.resolve(__dirname,'./src/images'),
to : './images'
}]),
// 构建后清除原有dist插件
new CleanWebpackPlugin('./dist',{
verbose: true,
dry: false
}),
new ExtractTextPlugin('style.css')
]
}
给定2个超出位数的正整数字符串,求它们和(大数相加)
原理:如同列竖式计算,把字符串分割为数组(JS中String对象不能直接通过下标修改,也没有StringBuffer这种东西),从最后往前加和。位数不同时低位需要补0(这个可以优化)
function add(strA, strB) {
const b = strB.split(''), a = strA.split('')
const bitDiff = a.length - b.length; //补零个数
const needAdd = bitDiff > 0 ? b : a; // 需要补零的数组
for (var i = 0; i < Math.abs(bitDiff); i++) {
needAdd.unshift('0')
}
let bit = a.length - 1; //从个位算起
let cache = 0; // 是否需要进位
while (bit > 0 ) {
var sum = parseInt( a[bit] ) + parseInt( b[bit] ) + cache;
b[bit] = (sum%10) + ''; //先加个位
cache = sum < 10? 0 : 1
bit --;
}
b[bit] = parseInt( a[bit] ) + parseInt( b[bit] ) + cache; //处理最高位
return b.join('');
}
var a = '11111111111111111111111111111', b = '555555555'
console.log('result--:' + r)
根据下面代码预期效果,实现Iterable
函数
for (const [key, value] of Iterable({a:1, b:2, c:3}) ) {
console.log(key, value) // 输出 a 1; b 2; c 3
}
解法: 这个题目按实现的方式可以判断一个人对JavaScript迭代的理解程度,这里提供一个基于Symbol.iterator
的解法:
const Iterable = (object, callback) => {
const assignable = !object[Symbol.iterator]
console.assert(assignable, 'iterator already existed')
if (!assignable) {
return object;
}
object[Symbol.iterator] = typeof callback === 'function' ? callback : function* () {
for (const key of Object.keys(this)) {
yield [key, this[key]];
}
};
return object;
};
网友评论