JS 常见手写面试题
instance
javascript
function myInstance(left, right) {
let proto = Object.getPrototypeOf(left);
let prototype = right.prototype;
while (true) {
if (!proto) return false;
if (proto === prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}
0.1+0.2!=0.3
javascript
0.1 + 0.2 - 0.3 < Number.EPSILON
true
new
javascript
function objectFactory() {
let obj = new Object();
let Constructor = [].shift.call(arguments);
obj.__proto__ = Constructor.prototype;
let ret = Constructor.apply(obj, arguments);
return typeof ret === 'object' ? ret || obj : obj;
};
Ajax
javascript
{
const XMLHttpRequest = require('xhr2');
let server_url = 'http://justin3go.cc:8000/api/v1/docs/search';
let xhr = new XMLHttpRequest();
xhr.open('GET',server_url);
xhr.onreadystatechange = function(){
if(this.readyState !== 4)return;
if(this.status === 200){
// handle(this.response);
}else{
console.error(this.statusText);
}
}
xhr.onerror = function(){
console.error(this.statusText);
}
xhr.responseType = 'json';
xhr.setRequestHeader('Header', 'application/json')
xhr.send('q=python&p=1')
}
使用 promise 封装 Ajax
javascript
{
const XMLHttpRequest = require('xhr2');
function getJson(url, params) {
let promise = new Promise((reslove, reject)=>{
let xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = function(){
if(this.readyState !== 4)return;
if(this.status === 200){
reslove(this.response)
}else{
reject(this.statusText)
}
}
xhr.onerror = function(){
reject(this.statusText)
}
xhr.responseType = 'json';
xhr.setRequestHeader('Header', 'application/json');
xhr.send(params)
})
return promise;
}
}
call,apply,bind
javascript
Function.prototype.myCall = function (context) {
if (typeof this !== 'function') {
console.error('type error');
}
let args = [...arguments].slice(1),
res = null;
context = context || window;
context.fn = this;
res = context.fn(...args);
delete context.fn;
return res;
}
javascript
Function.prototype.myApply = function(context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
let result = null;
// 判断 context 是否存在,如果未传入则为 window
context = context || window;
// 将函数设为对象的方法
context.fn = this;
// 调用方法
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
// 将属性删除
delete context.fn;
return result;
};
javascript
Function.prototype.myBind = function(context) {
// 判断调用对象是否为函数
if (typeof this !== "function") {
throw new TypeError("Error");
}
// 获取参数
var args = [...arguments].slice(1),
fn = this;
return function Fn() {
// 根据调用方式,传入不同绑定值
return fn.apply(
this instanceof Fn ? this : context, // new 该函数的话使 this 的优先级更高
args.concat(...arguments)
);
};
};
判断是否为数组的几种方式
javascript
{
let a = [1, 2, 3]
// 一般来说至少记住前三种
console.log(a instanceof Array);
console.log(Array.isArray(a));
console.log(Object.prototype.toString.call(a).slice(8,-1) === 'Array');
console.log(a.__proto__ === Array.prototype);
console.log(Array.prototype.isPrototypeOf(a));
}
true
true
true
true
true
null
javascript
console.log(null === undefined);
console.log(null == undefined);
console.log(typeof null); // 但同时 null 也是基本数据类型的一种
console.log(typeof function(){;}); // function 不是基本数据类型
false
true
object
function
判断是否为 NAN
javascript
{
let a = NaN;
console.log(Number.isNaN(a)); // 与全局的 isNaN 方法相比这个不会进行类型转换,一般用这个
console.log(!(a == a)); // 利用 NAN 不等于自身这个特性,其它的没这个特性
}
true
true
promises.all
javascript
Promise.all = function(promiseArr){
let index = 0,result = [];
return new Promise((resolve, reject)=>{
promiseArr.forEach((p, i, arr) => {
Promise.resolve(p).then(val =>{ // 这个 peomise.reslove 空包装有什么好处吗,解决这一种情况:传入的是普通值:7
index++;
result[i] = val;
if(index === promiseArr.length){
resolve(result);
}
},err=>{
reject(err);
})
});
})
}
promises.race
javascript
Promise.race = function(promiseArr) {
return new Promise((resolve, reject) => {
promiseArr.forEach(p => {
Promise.resolve(p).then(val => {
resolve(val)
}, err => {
reject(err)
})
})
})
}
防抖
javascript
function debounce(fn, wait) {
var timer = null; // 这里的关键就在于需要使用一个闭包来存储这个 timer 计时器
return function() {
var context = this,
args = [...arguments];
// 如果此时存在定时器的话,则取消之前的定时器重新记时
if (timer) {
clearTimeout(timer);
timer = null;
}
// 设置定时器,使事件间隔指定事件后执行
timer = setTimeout(() => {
fn.apply(context, args);
}, wait);
};
}
节流
javascript
// 定时器版
function throttle (fun, wait){
let timeout = null
return function(){
let context = this
let args = [...arguments]
if(!timeout){
timeout = setTimeout(() => {
fun.apply(context, args)
timeout = null
}, wait)
}
}
}
懒加载的实现
javascript
{/* <div class="container">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
</div>
<script> */}
var imgs = document.querySelectorAll('img');
function lozyLoad() {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var winHeight = window.innerHeight;
for (var i = 0; i < imgs.length; i++) {
if (imgs[i].offsetTop < scrollTop + winHeight) {
imgs[i].src = imgs[i].getAttribute('data-src');
}
}
}
window.onscroll = lozyLoad();
// </script>
JSONP 实现跨域
javascript
{/* <script> */}
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
document.head.appendChild(script);
// 回调执行函数
function handleCallback(res) {
alert(JSON.stringify(res));
}
// </script>
函数柯里化
javascript
function curry(fn) {
let judge = (...args) => {
if (args.length == fn.length) return fn(...args)
return (...arg) => judge(...args, ...arg)
}
return judge
}
// 先调用 addCurry(1), judge 会搜集其参数,但不执行 fn,然后依次调用(addCurry(1))(2)...直到搜集的参数达到 add 参数的个数
javascript
function add(a, b, c) {
return a + b + c
}
add(1, 2, 3)
let addCurry = curry(add)
addCurry(1)(2)(3)
6