面试中手写JS代码

手写防抖(Debouncing)和节流(Throttling)

防抖(Debouncing)实现

  • 典型例子:限制鼠标连击触发、监听用户输入

解释:当一次事件发生后,事件处理器要等一定阀值的时间,如果这段时间过去后,再也没有事件发生,就处理最后一次发生的事件。如果还差0.01秒到达指定事件,这是又有一次事件触发,那么之前的等待作废,需要重新再次等待指定时间。

//防抖动函数
function debounce(fn, wait = 50, immediate) {

	let timer;
	
	return function() {
	
		if (immediate) {
		
		fn.apply(this, arguments)
		}
		
		if (timer) clearTimeout(timer)
		
		timer = setTimeout() => {
		
			fn.apply(this, arguments)
			
		},wait)
	}
}
节流(Throttling)实现

解释:可以理解为事件再一个管道中传输,加上这个节流阀之后,事件的流速就会减慢,节流可以将一个函数的调用频率限制再一定阀值内,例如 1s ,那么 1s 内这个函数一定不会被调用两次。

//简单的节流函数
function throttle(fn, wait) {
	let prev = new Date();
	return function() { 	
	    const args = arguments;   
		const now = new Date();
		if (now - prev > wait) {
			fn.apply(this, args);
			prev = new Date();
		}
	}
}
手写一个JS深拷贝
  • 著名乞丐版

var newObj = JSON.parse ( JSON.stringify ( someObj ) );

  • 面试够用版
function deepCopy(obj) {
	if (typeof obj == "object") {
		//复杂数据类型
		var result = obj.constructor == Array ? [] : {};
		for (let i in obj) {
			result[i] = typeof obj[i] == "object" ? deepCopy(obj[i] : obj[i])
		}
	} else {
	//简单数据类型
		var result = obj
	}
	return result
}
手写一个Promise
  • 三种状态 pending | fulfilled(resolved) | rejected
  • 当处于 pending 状态的时候,可以转移到 fulfilled(resolved)或者rejected状态
  • 当处于fulfilled(resolved)状态或者rejected状态时候,就不可变。
  • 必须有一个then的异步执行方法,then接受两个参数onFulfilled、onRejected

基础版 代码实现:

function myPromise(constructor){
    let self=this;
    self.status="pending" //定义状态改变前的初始状态
    self.value=undefined;//定义状态为resolved的时候的状态
    self.reason=undefined;//定义状态为rejected的时候的状态
    function resolve(value){
        //两个==="pending",保证了状态的改变是不可逆的
       if(self.status==="pending"){
          self.value=value;
          self.status="resolved";
       }
    }
    function reject(reason){
        //两个==="pending",保证了状态的改变是不可逆的
       if(self.status==="pending"){
          self.reason=reason;
          self.status="rejected";
       }
    }
    //捕获构造异常
    try{
       constructor(resolve,reject);
    }catch(e){
       reject(e);
    }
}

//同时再myPromise的原型上定义链式调用的then方法:

myPromise.prototype.then=function(onFullfilled,onRejected){
   let self=this;
   switch(self.status){
      case "resolved":
        onFullfilled(self.value);
        break;
      case "rejected":
        onRejected(self.reason);
        break;
      default:       
   }
}
实现 instanceof
function instanceof (left, right) {
	let proto = left.__proto__;
	let prototype = right.prototype
	while (true) {
		if (proto === null) return false
		if (proto === prototype) return true
		proto = proto.__proto__;
	}
}
js继承的几种实现方式

首先,我们需要定义一个父类:

//定义一个动物类
function Animal (name) {
//属性
	this.name = name || 'Animal';
	//实例方法
	this.sleep = function() {
	console.log(this.name + 'i'm sleeping')
	}
}
//原型方法
Animal.prototype.eat = function(food) {
	console.log(this.name + 'i'm eating' + food)
}
  • 原型链继承
function Parent2 () {
	this.name = 'parent2'
}
function Child2 () {
	this.sex = 'male'
}
Child2.prototype = new Parent2()
console.log(new Child2())
  • 构造函数继承
function Parent1 () {
	this.name = 'parent1'
}
Parent1.prototype.say = function(){};
function Child1() {
	Parent1.call(this)
	this.sex = 'male'
}
console.log(new Child1())
  • 实例继承
  • 拷贝继承
  • 组合继承
function Cat(name) {
	Animal.call(this)
	this.name = name || 'tom'
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
//Cat.prototype = Animal.prototype
// Text code
var cat = new Cat()
console.log(cat.name)
console.log(cat.sleep())
console.log(cat instanceof Animal)	//true
console.log(cat instanceof Cat)	//true
  • 寄生组合继承
function Cat(name) {
	Animal.call(this);
	this.name = name || 'Tom'
}
(function(){
	// 创建一个没有实例的类
	var Super = function() {
	Super.prototype = Animal.prototype;
	//将实例作为子类的原型
	Cat.prototype = new Super();
})();
Cat.prototype.constructor = Cat;
// Text Code
var cat = new Cat();
console.log(cat.name)
console.log(cat.sleep)
console.log(cat instanceof Animal)		//true
console.log(cat instanceof Cat)		//true

js函数柯里化

//求和
let add = function (a, b, c) {
	return a + b +c
}
function curry(fn) {
	//闭包
	//缓存除函数fn之外的所有参数
	let args = Array.prototype.slice.call(arguments, 1)
	return function() {
		//连接已经缓存的老的参数和新传入的参数(就是把每次传入的参数都先保存下来,但是并不执行)
		let newArgs = args.concat(Array.from(arguments))
		if (newArgs.length < fn.length) {
			return curry.call(this, fn, ...newArgs)
		} else {
		//调用
		return fn.apply(this, newArgs)
		}
	}
}
let f = curry(add)
console.log('柯里化',f(1)(2)(3))
console.log('柯里化',f(1, 2)(3))
console.log('柯里化',f(1, 2, 3))
原生js封装ajax
function ajax(options) {
	var xhr = null;
	var params = formsParams(options, data);
	//创建对象
	if (window.XMLHttpRequest()) {
		xhr = new XMLHttpRequest()
	} else {
		xhr = new ActiveXObject("Microsoft.XMLHTTP");
	}
	//连接
	if (options.type === "GET") {
		xhr.open(options.type, options.url + "?" +params, options.async);
		xhr.send(null)
	} else if (options.type === "POST") {
		xhr.open(options.type, options.url, options.async);
		xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		xhr.send(params);
	}
	//判断状态
	xhr.onreadystateChange = function() {
		if (xhr.readyState === 4 && xhr.status ===200) {
			options.success(xhr.responseText);
		}
	function formParams(data) {
		var arr = [];
		for (var prop in data) {
			arr.push(prop + "=" + data[prop]);
		}
		return arr.join("&");
	}
	}
}
//调用
ajax({
	url: "time.php",
	type: "POST",
	async: true,
	data: {
		name: "Tom",
		age: 18
	},
	success: function(data) {
		console.log(data);
	}
})
手写jsonp

跨域通信的几种方式:jsonp、hash、postMessage、webSocket、CORS

(function (window,document) {
    "use strict";
    var jsonp = function (url,data,callback) {

        // 1.将传入的data数据转化为url字符串形式
        // {id:1,name:'zhangsan'} => id=1&name=zhangsan
        var dataString = url.indexof('?') == -1? '?': '&';
        for(var key in data){
            dataString += key + '=' + data[key] + '&';
        };

        // 2 处理url中的回调函数
        // cbFuncName回调函数的名字 :my_json_cb_名字的前缀 + 随机数(把小数点去掉)
        var cbFuncName = 'my_json_cb_' + Math.random().toString().replace('.','');
        dataString += 'callback=' + cbFuncName;

        // 3.创建一个script标签并插入到页面中
        var scriptEle = document.createElement('script');
        scriptEle.src = url + dataString;

        // 4.挂载回调函数
        window[cbFuncName] = function (data) {
            callback(data);
            // 处理完回调函数的数据之后,删除jsonp的script标签
            document.body.removeChild(scriptEle);
        }

        // 5.append到页面中
        document.body.appendChild(scriptEle);
    }

    // 因为jsonp是一个私有函数外部不能调用,所有jsonp函数作文window对象的一个方法,供外部调用
    window.$jsonp = jsonp;

})(window,document)

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值