前言

1. 烈熊网络

这家公司其实我也没有太了解过,是我前同事推荐的,说里面的薪资待遇不错,然后我当时也有空闲时间,所以就去试试了,虽然公司名气没有上面提到的公司大,但是他的面试题我觉得还是挺有分量的。

1.1 请说出下面代码的执行顺序

async function async1() {   console.log(1); const result = await async2(); console.log(3);
}
async function async2() {   console.log(2);
}
Promise.resolve().then(() => {  console.log(4);
});
setTimeout(() => {  console.log(5);
});
async1();
console.log(6);

我的回答是[1,2,6,4,3,5]。这道题目主要考对JS宏任务微任务的理解程度,JS的事件循环中每个宏任务称为一个Tick(标记),在每个标记的末尾会追加一个微任务队列,一个宏任务执行完后会执行所有的微任务,直到队列清空。上题中我觉得稍微复杂点的在于async1函数,async1函数本身会返回一个Promise,同时await后面紧跟着async2函数返回的Promise, console.log(3)其实是在async2函数返回的Promise的then语句中执行的,then语句本身也会返回一个Promise然后追加到微任务队列中,所以在微任务队列中 console.log(3)console.log(4)后面,不太清楚的同学可以网上查下资料或者关注我的公众号「前端之境」,我们可以一起交流学习。

1.2 手动实现Promise,写出伪代码

幸运的是在面试前刚好查阅了下这部分的资料,所以回答过程中还算得心应手,主要是需要遵循Promise/A+规范:

// onFulfilled在状态由pending -> fulfilled(resolved) 时执行,参数为resolve()中传递的值
// onRejected在状态由pending -> rejected 时执行,参数为reject()中传递的值
promise.then(onFulfilled,onRejected)

(3) then方法必须返回一个promise:

promise2 = promise1.then(onFulfilled, onRejected);

实现代码直接贴出来吧:

参考自:实现一个完美符合Promise/A+规范的Promise

地址:https://github.com/forthealllight/blog/issues/4

function myPromise(constructor){  let self=this; self.status="pending" //定义状态改变前的初始状态 self.value=undefined;//定义状态为resolved的时候的状态 self.reason=undefined;//定义状态为rejected的时候的状态    self.onFullfilledArray=[]; self.onRejectedArray=[];   function resolve(value){    if(self.status==="pending"){   self.value=value;  self.status="resolved";  self.onFullfilledArray.forEach(function(f){ f(self.value);  //如果状态从pending变为resolved,    //那么就遍历执行里面的异步方法    }); }   }   function reject(reason){    if(self.status==="pending"){   self.reason=reason;    self.status="rejected";  self.onRejectedArray.forEach(function(f){   f(self.reason); //如果状态从pending变为rejected,    //那么就遍历执行里面的异步方法    })  }   }   //捕获构造异常    try{    constructor(resolve,reject);    }catch(e){  reject(e);  }
}
myPromise.prototype.then=function(onFullfilled,onRejected){    let self=this; let promise2;   switch(self.status){    case "pending":   promise2 = new myPromise(function(resolve,reject){ self.onFullfilledArray.push(function(){ setTimeout(function(){  try{    let temple=onFullfilled(self.value);   resolvePromise(temple)  }catch(e){  reject(e) //error catch }   })  }); self.onRejectedArray.push(function(){   setTimeout(function(){  try{    let temple=onRejected(self.reason);    resolvePromise(temple)  }catch(e){  reject(e)// error catch }   })  }); })  case "resolved":  promise2=new myPromise(function(resolve,reject){   setTimeout(function(){  try{    let temple=onFullfilled(self.value);   //将上次一then里面的方法传递进下一个Promise状态  resolvePromise(temple); }catch(e){  reject(e);//error catch }   })  })  break;  case "rejected":  promise2=new myPromise(function(resolve,reject){   setTimeout(function(){  try{    let temple=onRejected(self.reason);    //将then里面的方法传递到下一个Promise的状态里   resolvePromise(temple);     }catch(e){  reject(e);  }   })  })  break;  default:        }   return promise2;
}
function resolvePromise(promise,x,resolve,reject){  if(promise===x){ throw new TypeError("type error") }   let isUsed; if(x!==null&&(typeof x==="object"||typeof x==="function")){ try{    let then=x.then;   if(typeof then==="function"){  //是一个promise的情况 then.call(x,function(y){    if(isUsed)return;   isUsed=true;   resolvePromise(promise,y,resolve,reject);   },function(e){  if(isUsed)return;   isUsed=true;   reject(e);  })  }else{  //仅仅是一个函数或者是对象  resolve(x)  }   }catch(e){  if(isUsed)return;   isUsed=true;   reject(e);  }   }else{  //返回的基本类型,直接resolve  resolve(x)  }
}

1.3 请说出以下打印结果

let a = {a: 10};
let b = {b: 10};
let obj = {    a: 10
};
obj[b] = 20;
console.log(obj[a]);

我的回答是:20。这道题目主要考对JS数据类型的熟练度以及对ES6中属性名表达式的理解。在上题中 obj[b]=20的赋值操作后, obj其实已经变成了 {a:10,[objectObject]:20},这是因为如果属性名表达式是一个对象的话,那么默认情况下会自动将对象转为字符串 [objectObject],最后一步获取 obj[a]时,a本身也是一个对象,所以会被转换为获取 obj[objectObject]也就是上一步赋值的20。

1.4 说出几种数组去重的方式

这个其实网上已经有大把大把的实现方案了,我也就大概给出了以下几种:

let originalArray = [1,2,3,4,5,3,2,4,1];
// 方式1
const result = Array.from(new Set(originalArray));
console.log(result); // -> [1, 2, 3, 4, 5]
// 方式2
const result = [];
const map = new Map();
for (let v of originalArray) {  if (!map.has(v)) {  map.set(v, true);   result.push(v); }
}
console.log(result); // -> [1, 2, 3, 4, 5]
// 方式3
const result = [];
for (let v of originalArray) {  if (!result.includes(v)) {  result.push(v); }
}
console.log(result); // -> [1, 2, 3, 4, 5]
// 方式4
for (let i = 0; i < originalArray.length; i++) {  for (let j = i + 1; j < originalArray.length; j++) { if (originalArray[i] === originalArray[j]) { originalArray.splice(j, 1); j--;    }   }
}
console.log(originalArray); // -> [1, 2, 3, 4, 5]
// 方式5
const obj = {};
const result = originalArray.filter(item => obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true));
console.log(result); // -> [1, 2, 3, 4, 5]

1.5 对象数组如何去重?

这个题目不只一家公司问到了,开始的时候一脸懵逼,心里想着每个对象的内存地址本身就不一样,去重的意义何在,非要去重的话,那只能通过 JSON.stringify序列化成字符串(这个方法有一定的缺陷)后进行对比,或者递归的方式进行键-值对比,但是对于大型嵌套对象来说还是比较耗时的,所以还是没有答好,后来面试官跟我说是根据每个对象的某一个具体属性来进行去重,因为考虑到服务端返回的数据中可能存在id重复的情况,需要前端进行过滤,如下:

const responseList = [  { id: 1, a: 1 },    { id: 2, a: 2 },    { id: 3, a: 3 },    { id: 1, a: 4 },
];
const result = responseList.reduce((acc, cur) => { const ids = acc.map(item => item.id);  return ids.includes(cur.id) ? acc : [...acc, cur];
}, []);
console.log(result); // -> [ { id: 1, a: 1}, {id: 2, a: 2}, {id: 3, a: 3} ]

2. 携程

当时是前一天进行了一次电面,然后第二天现场面,两个面试官轮流问,大概持续了一个半小时吧,问的问题还是比较多的,有些问题时间久了还是不太记得了,多多见谅!

2.1 理解深拷贝和浅拷贝吗?

浅拷贝是指创建一个对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,那么拷贝的就是基本类型的值,如果属性是引用类型,那么拷贝的就是内存地址,所以如果其中一个对象修改了某些属性,那么另一个对象就会受到影响。深拷贝是指从内存中完整地拷贝一个对象出来,并在堆内存中为其分配一个新的内存区域来存放,并且修改该对象的属性不会影响到原来的对象。

2.2 深拷贝和浅拷贝的实现方式分别有哪些?

浅拷贝:(1) Object.assign的方式 (2) 通过对象扩展运算符 (3) 通过数组的slice方法 (4) 通过数组的concat方法。

2.3 大概说下实现无缝轮播的思路?

先简单说了下实现轮播的思路,多张图片从左至右依次排列,点击左右侧按钮切换图片的时候,让图片的父级容器的left偏移值增加或减少单张图片的宽度大小,同时配合CSS3 transition过渡或者手写一个动画函数,这样可以实现一个比较平滑的动画效果。对于无缝轮播,我当时的思路是再拷贝一个图片的父级容器出来,例如原来一个 <ul><li></li><li></li></ul>对应两张图片,现在变为两个 ul对应4张图片,同时 ul的父容器监听自身的 scrollLeft,如果值已经大于等于一个 ul的宽度,则立即将自身的 scrollLeft值重置为0,这样就又可以从起点开始轮播,实现无缝的效果。

2.3 说出以下代码的执行结果

  var a = 10;    var obj = {    a: 20,  say: function () {  console.log(this.a);    }   };  obj.say();

这个是被我简化后的版本,具体题目记不太清了,反正就是考的this的指向问题,上题中答案为20。然后面试官继续追问,如何才能打印出10,给出如下方式:

  // 方式1 var a = 10;    var obj = {    a: 20,  say: () => {  // 此处改为箭头函数   console.log(this.a);    }   };  obj.say(); // -> 10  // 方式2  var a = 10;    var obj = {    a: 20,  say: function () {  console.log(this.a);    }   };  obj.say.call(this); // 此处显示绑定this为全局window对象    // 方式3  var a = 10;    var obj = {    a: 20,  say: function () {  console.log(this.a);    }   };  var say = obj.say; // 此处先创建一个临时变量存放函数定义,然后单独调用  say();

2.4 Vue的生命周期有哪些?

创建:beforeCreate,created;

2.5 移动端如何设计一个比较友好的Header组件?

当时的思路是头部(Header)一般分为左、中、右三个部分,分为三个区域来设计,中间为主标题,每个页面的标题肯定不同,所以可以通过vue props的方式做成可配置对外进行暴露,左侧大部分页面可能都是回退按钮,但是样式和内容不尽相同,右侧一般都是具有功能性的操作按钮,所以左右两侧可以通过vue slot插槽的方式对外暴露以实现多样化,同时也可以提供default slot默认插槽来统一页面风格。

2.6 说出space-between和space-around的区别?

这个是flex布局的内容,其实就是一个边距的区别,按水平布局来说, space-between在左右两侧没有边距,而 space-around在左右两侧会留下边距,垂直布局同理,如下图所示:

2.7 你所知道的前端性能优化方案

这个其实方案还是比较多的,可以从DOM层面CSS样式层面JS逻辑层面分别入手,大概给出以下几种:重绘回流,任何会导致重绘回流的操作都应减少执行,可将多次操作合并为一次事件委托的方式进行事件绑定,避免大量绑定导致内存占用过多;扁平化,避免过多的层级嵌套,尽量使用特定的选择器来区分;动画属性来实现,开启GPU硬件加速;指定宽高或者脱离文档流,可避免加载后的重新计算导致的页面回流;<head>标签中引入,js文件在 <body>标签中引入,优化关键渲染路径CDN加载静态资源,合理使用浏览器强缓存协商缓存,小图片可以使用Base64来代替,合理使用浏览器的预取指令prefetch预加载指令preload压缩混淆代码删除无用代码代码拆分来减少文件体积;小图片使用雪碧图,图片选择合适的质量尺寸格式,避免流量浪费。

2.8 git多人协作时如何解决冲突

冲突主要是出现在多人在修改同一个文件的同一部分内容时,对方当你之前 push,然后你后 push的时候git检测到两次提交内容不匹配,提示你 Conflict,然后你 pull下来的代码会在冲突的地方使用 =====隔开,此时你需要找到对应的开发人员商量代码的取舍,切不可随意修改并强制提交,解决冲突后再次 push即可。

3. 喜马拉雅

当时是两轮技术面,一次电面,一次现场面,电面有部分题目还是答得很模糊,现场面自我感觉还可以吧。

3.1 手动实现一个bind方法

代码如下:

Function.prototype.bind = function(context, ...args1) {   if (typeof this !== 'function') {   throw new Error('not a function');    }   let fn = this; let resFn = function(...args2) {   return fn.apply(this instanceof resFn ? this : context, args1.concat(args2));   };  const DumpFunction = function DumpFunction() {};   DumpFunction.prototype = this.prototype;   resFn.prototype = new DumpFunction();  return resFn;
}

3.2 说说对React Hooks的理解

在React中我们一般有两种方式来创建组件,类定义或者函数定义;在类定义中我们可以使用许多React的特性,比如state或者各种生命周期钩子,但是在函数定义中却无法使用。所以在React 16.8版本中新推出了React Hooks的功能,通过React Hooks我们就可以在函数定义中来使用类定义当中才能使用的特性。当然React Hooks的出现本身也是为了组件复用,以及相比于类定义当中的生命周期钩子,React Hooks中提供的 useEffect将多个生命周期钩子进行结合,使得原先在类定义中分散的逻辑变得更加集中,方便维护和管理。

3.3 React Hooks当中的useEffect是如何区分生命周期钩子的

useEffect可以看成是 componentDidMountcomponentDidUpdatecomponentWillUnmount三者的结合。useEffect(callback,[source])接收两个参数,调用方式如下:

 useEffect(() => {    console.log('mounted');   return () => {  console.log('willUnmount');   }   }, [source]);

生命周期函数的调用主要是通过第二个参数 [source]来进行控制,有如下几种情况:[source]参数不传时,则每次都会优先调用上次保存的函数中返回的那个函数,然后再调用外部那个函数;[source]参数传 []时,则外部的函数只会在初始化时调用一次,返回的那个函数也只会最终在组件卸载时调用一次;[source]参数有值时,则只会监听到数组中的值发生变化后才优先调用返回的那个函数,再调用外部的函数。

3.4 什么是高阶组件(HOC)

高阶组件(Higher Order Componennt)本身其实不是组件,而是一个函数,这个函数接收一个元组件作为参数,然后返回一个新的增强组件,高阶组件的出现本身也是为了逻辑复用,举个例子:

  function withLoginAuth(WrappedComponent) {  return class extends React.Component {  constructor(props) {    super(props);   this.state = { isLogin: false  };  }   async componentDidMount() { const isLogin = await getLoginStatus();    this.setState({ isLogin }); }   render() {  if (this.state.isLogin) {   return <WrappedComponent {...this.props} />;  }   return (<div>您还未登录...</div>);   }   }   }

3.5 说出以下代码的执行结果

parseInt('2017-07-01') // -> 2017
parseInt('2017abcdef') // -> 2017
parseInt('abcdef2017') // -> NaN

3.6 React实现的移动应用中,如果出现卡顿,有哪些可以考虑的优化方案

(1) 增加 shouldComponentUpdate钩子对新旧 props进行比较,如果值相同则阻止更新,避免不必要的渲染,或者使用 PureReactComponent替代 Component,其内部已经封装了 shouldComponentUpdate的浅比较逻辑;key属性,以方便React的 diff算法中对该节点的复用,减少节点的创建和删除操作;render函数中减少类似 onClick={()=>{doSomething()}}的写法,每次调用 render函数时均会创建一个新的函数,即使内容没有发生任何变化,也会导致节点没必要的重渲染,建议将函数保存在组件的成员对象中,这样只会创建一次;props如果需要经过一系列运算后才能拿到最终结果,则可以考虑使用 reselect库对结果进行缓存,如果 props值未发生变化,则结果直接从缓存中拿,避免高昂的运算代价;webpack-bundle-analyzer分析当前页面的依赖包,是否存在不合理性,如果存在,找到优化点并进行优化。

3.7 (算法题) 如何从10000个数中找到最大的10个数

这题没答好,两个字形容:稀烂!一碰到算法题就容易紧张蒙圈,来个正解吧。

创建一个最小堆结构,初始值为10000个数的前10个,堆顶为10个数里的最小数。然后遍历剩下的9990个数,如果数字小于堆顶的数,则把堆顶的数删除,将遍历的数插入堆中。堆结构会自动进行调整,所以可以保证堆顶的数一定是10个数里最小的。遍历完毕后,堆里的10个数就是这10000个数里面最大的10个。

4. 流利说

当时是提前有一次电面,然后过了几天才去现场面,现场两轮技术面,公司很注重底层原理,所以答得不是很好。

4.1 React实现一个防抖的模糊查询输入框

代码如下:

  // 防抖函数 function debounce(fn, wait, immediate) {    let timer = null;  return function (...args) { let context = this;    if (immediate && !timer) {  fn.apply(context, args);    }   if (timer) clearTimeout(timer); timer = setTimeout(() => { fn.apply(context, args);    }, wait);   }   }   class SearchInput extends React.Component { constructor(props) {    super(props);   this.state = { value: '' };  this.handleChange = this.handleChange.bind(this);  this.callAjax = debounce(this.callAjax, 500, true);    }   handleChange(e) {   this.setState({ value: e.target.value   }); this.callAjax();    }   callAjax() {    // 此处根据输入值调用服务端接口   console.log(this.state.value);  }   render() {  return (<input type="text" value={this.state.value} onChange={this.handleChange} />);    }   }

4.2 手动封装一个请求函数,可以设置最大请求次数,请求成功则不再请求,请求失败则继续请求直到超过最大次数

代码如下:

  function request(url, body, successCallback, errorCallback, maxCount = 3) {    return fetch(url, body) .then(response => successCallback(response) .catch(err => { if (maxCount <= 0) return errorCallback('请求超时');  return request(url, body, successCallback, errorCallback, --maxCount);  }); }   // 调用   request('https://some/path', { method: 'GET', headers: {} }, (response) => {    console.log(response.json());   }, (err) => console.error(err));

4.3 JS中==和===的区别

==表示抽象相等,两边值类型不同的时候,会先做隐式类型转换,再对值进行比较;===表示严格相等,不会做类型转换,两边的类型不同一定不相等。

4.4 GET和POST的区别

(1) GET请求在浏览器回退和刷新时是无害的,而POST请求会告知用户数据会被重新提交;

4.5 说下浏览器的缓存机制

浏览器的缓存机制可分为强缓存协商缓存,服务端可以在响应头中增加Cache-Control/Expires来为当前资源设置缓存有效期(Cache-Control的max-age的优先级高于Expires),浏览器再次发送请求时,会先判断缓存是否过期,如果未过期则命中强缓存,直接使用浏览器的本地缓存资源,如果已过期则使用协商缓存,协商缓存大致有以下两种方案:Etag(服务端响应携带) & If-None-Match(客户端请求携带)Last-Modified(服务端响应携带) & If-Modified-Since (客户端请求携带) ,其优先级低于Etag304通知浏览器使用本地缓存,如果不一致则返回新的资源。

5. 哔哩哔哩

现场两轮技术面,问了很多考验基础知识的题目,整体来说回答的还算比较满意吧。

5.1 CSS3中transition和animation的属性分别有哪些

transition 过渡动画:transition-property:属性名称transition-duration: 间隔时间transition-timing-function: 动画曲线transition-delay: 延迟

animation 关键帧动画:animation-name:动画名称animation-duration: 间隔时间animation-timing-function: 动画曲线animation-delay: 延迟animation-iteration-count:动画次数animation-direction: 方向animation-fill-mode: 禁止模式

5.2 盒模型

指的是页面在渲染时,DOM元素所采用的布局模型,一个元素占用的空间大小由几个部分组成,内容(content)、内边距(padding),边框(border)和外边距(margin)。可以通过 box-sizing来进行设置,其中IE盒模型的content包含了padding和border,这是区别于W3C标准盒模型的地方。

5.3 选择器优先级

!important > 行内样式 > id选择器 > class选择器 > 标签选择器 > * > 继承 > 默认

5.4 forEach,map和filter的区别

forEach遍历数组,参数为一个回调函数,回调函数接收三个参数,当前元素,元素索引,整个数组;mapforEach类似,遍历数组,但其回调函数的返回值会组成一个新数组,新数组的索引结构和原数组一致,原数组不变;filter会返回原数组的一个子集,回调函数用于逻辑判断,返回 true则将当前元素添加到返回数组中,否则排除当前元素,原数组不变。

5.5 实现函数柯里化

代码如下:

const curry = (fn, ...args1) => (...args2) => (   arg => arg.length === fn.length ? fn(...arg) : curry(fn, ...arg)
)([...args1, ...args2]);
// 调用
const foo = (a, b, c) => a * b * c;
curry(foo)(2, 3, 4); // -> 24
curry(foo, 2)(3, 4); // -> 24
curry(foo, 2, 3)(4); // -> 24
curry(foo, 2, 3, 4)(); // -> 24

5.6 跨标签页的通讯方式有哪些

(1) BroadCast Channel

5.7 实现一个函数判断数据类型

代码如下:

function getType(obj) { if (obj === null) return String(obj);    return typeof obj === 'object'     ? Object.prototype.toString.call(obj).replace('[object ', '').replace(']', '').toLowerCase()    : typeof obj;
}
// 调用
getType(null); // -> null
getType(undefined); // -> undefined
getType({}); // -> object
getType([]); // -> array
getType(123); // -> number
getType(true); // -> boolean
getType('123'); // -> string
getType(/123/); // -> regexp
getType(new Date()); // -> date

总结

有些面试题实在是想不起来了,上面的题目其实大部分还是比较基础的,问到的频率也比较高,这里只是做一个简单的分享,希望对大家多多少少有点帮助,也希望能和大家一起交流学习。

喜马拉雅、ctrip、b站、流利说、蜻蜓FM、爱回收前端面试经历相关推荐

  1. B站、喜马拉雅、流利说、蜻蜓FM、爱回收等前端面试经历

    点击上方"IT平头哥联盟",选择"置顶或者星标" 你的关注意义重大! 前言 2019年6月中旬,实在厌倦了之前平平淡淡的工作和毫不起眼的薪资,不顾亲人的反对,毅 ...

  2. 喜马拉雅忙着上市,蜻蜓FM忙着融资

    配图来自Canva可画 在线音频三巨头"喜马拉雅.蜻蜓FM.荔枝"从并驾齐驱到渐行渐远,发生了什么? 2020年1月,荔枝拿下"国内在线音频行业第一股"的称号: ...

  3. 荔枝FM、喜马拉雅FM、蜻蜓FM竞品分析

    荔枝FM.喜马拉雅FM.蜻蜓FM竞品分析 背景: 电台应用近年来越来越火爆,继视频之后音频大有成为下一片蓝海之势. 这里介绍三款FM应用,选取这三款一方面他们是电台应用中用户日均使用时长最多的三个应用 ...

  4. 蜻蜓FM涉嫌诈骗投资人和广告主源代码剖析

    引用自:https://github.com/cryfish2015/QingTingCheat 本文主要内容,引用自知乎的这篇文章:如何评价蜻蜓 FM 伪造用户活跃度等数据 感谢"左莫&q ...

  5. 蜻蜓FM战略项目经理程彤博:真实需求背后的供给关系

    嘉宾介绍 程彤博,美国University of Notre Dame MBA,创业者,用管理咨询思维分析互联网问题,前携程高级产品经理,现蜻蜓FM战略项目经理,脉脉原创作者. Q1. 有没有读过MB ...

  6. 失战于知识付费,会员与智能硬件将助蜻蜓FM打赢下半场战争?

    在线音频已经形成了喜马拉雅FM.蜻蜓FM.荔枝三足鼎立的局面. 知识付费这场战争,蜻蜓FM并未获胜 蜻蜓FM和喜马拉雅FM的成长路径非常相似,都是知识付费风口的弄潮儿.据了解,知识付费内容为蜻蜓FM贡 ...

  7. 蜻蜓FM回应恶意代码事件 音频行业仍将现721格局

    随着移动智能终端和车联网发展,音频行业逐渐积累到爆发风口,喜马拉雅FM.蜻蜓FM.考拉FM等当局者既是百家争鸣,同时免不了彼此争执.4月,多听 FM和荔枝FM两款网络电台APP突然被App Store ...

  8. JY播放器【蜻蜓FM电脑端,附带下载功能】

    今天给大家带来一款神器----JY播放器.可以不用打开网页就在电脑端听蜻蜓FM的节目,而且可以直接下载,对于我这种强迫症患者来说真的是神器.我是真的不喜欢电脑任务栏上面密密麻麻. 目前已经支持平台(蜻 ...

  9. 蜻蜓FM语音下载(qingtingdown)

    一.介绍 蜻蜓FM语音下载(qingtingdown),能够帮助你下载蜻蜓FM音频节目.如果你是蜻蜓FM会员,它还能帮你下载会员节目. 二.下载地址 本站下载:蜻蜓FM语音下载(qingtingdow ...

最新文章

  1. JUC系列(十一) | Java 8 CompletableFuture 异步编程
  2. SecureCRT 连接虚拟机Linux
  3. the NTP socket is in use, exiting
  4. 手工sql注入常规总结
  5. 厉害了!牛顿法深度学习优化器,效果比肩SGD和Adam
  6. 第九章 线程与内核对象的同步(4)
  7. splice方法_Array中splice用法
  8. 如何迅速的找到合适的开发者?
  9. 破解密码很难?利用Python自动编写暴力破解字典,黑客必学技能!
  10. Python PyQt5 教程
  11. 后危机时代,DCS的新征程
  12. 日本JAFFE表情库
  13. 10-20210308华为海思Hi3516DV300在鸿蒙系统下测试网络(以太网+WIFI)
  14. 优化模型验证关键代码06:多行程旅行商问题(mTSP)
  15. 徕卡 sl android app,相机入魔 徕卡SL DPReview测评结论
  16. 计算机就业去哪个岗位好? 算法岗位还是开发岗位更好?
  17. 笔记整理--玩转robots协议
  18. Android模拟器知识以及改造
  19. python3 setup.py install_安装Twisted执行python3 setup.py install报错
  20. tcp_timestamps tcp_tw_recycle引起的服务器连接不上问题

热门文章

  1. Tribonnbsp;Vitesse二次开发环境搭建
  2. 模拟电路51(模拟乘法器)
  3. Oracle建表时提示标识符无效
  4. Arduino学习(1)——基础入门
  5. ntp原理了解即可-小白笔记
  6. session会话中removeAttribute()和invalidate()的区别是什么
  7. php 区位码字符,PHP中实现汉字转区位码应用源码实例解析
  8. [小工具]-unbuntu20.04/16.04/18.04安装vncviewer及解决Linux error while loading shared libraries: libX11.so.6
  9. xcsrecommend
  10. C语言程序设计报告2000字,C语言程序设计报告.doc