Skip to content

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