前言

本文是面试系列篇的实现篇。笔者整理了面试过程中可能会遇到的手写实现,以及它的原理。这可以帮助面试者在笔试环节获得良好的加分。

其他文章系列,欢迎关注我文末的公众号

正文

apply和call

apply和call的实现中,主要是利用了两个点:

根据传入的thisArgs去创建对象

在新创建的对象上定义当前函数,然后进行调用

apply和call的区别:

apply在指定对象后只接受一个参数

call在指定对象后可以接受多个参数

代码实现如下:

/**

* apply模拟实现

*/

Function.prototype.myApply = function(thisArg, arrArg) {

//#1 类型检测

if (typeof this !== 'function') {

throw new TypeError(`${this}.apply is not a function`);

}

//#2 arrArg和thisArg参数判断

if (arrArg === undefined || arrArg === null) {

arrArg = [];

}

if (thisArg === undefined || thisArg === null) {

thisArg = _self;

}

//#3 创建对象,函数赋值,调用对象方法

const obj = new Object(thisArg);

obj['_fn_'] = this;

var result = obj['_fn_'](...arrArg);

delete obj['_fn_'];

return result;

}

/**

* call模拟实现

*/

Function.prototype.myCall = function(thisArg) {

//#1 类型检测

if (typeof this !== 'function') {

throw new TypeError(`${this}.call is not a function`);

}

//#2 参数调整

const argumentsArr = [];

for (let i = 1; i < arguments.length; i++) {

argumentsArr.push(arguments[i]);

}

if (thisArg === undefined || thisArg === null) {

thisArg = _self;

}

//#3 创建对象,函数赋值,调用对象函数

const obj = new Object(thisArg);

var _fn = '_fn_';

obj[_fn] = this;

var result = obj[_fn](...argumentsArr);

delete obj[_fn];

return result;

}

复制代码

bind和softBind实现

bind和softBind的区别:

bind的绑定对象是固定的,softBind相当于是一种软绑定【如果this为空,或者指向全局对象时,才改变函数的绑定】

bind和apply & call的区别:

bind返回一个函数;apply和call是调用时执行的

代码实现如下:

/**

* bind实现

*/

Function.prototype.myBind = function(obj) {

//#1 类型校验

if (typeof this === 'function') {

throw new TypeError(`${this}.bind is not a function`);

}

//#2 取参

const args = Array.prototype.shift.call(arguments) || [];

const fn = this;

//#3 定义函数,调用apply改变this指向,同时改变新函数的原型

var bindFn = function() {

return this.apply(obj, [].concat(args, arguments));

}

bindFn.prototype = fn.prototype;

return bindFn;

}

/**

* softBind的实现

*/

Function.prototype.softBind = function(obj) {

//#1 类型校验

if (typeof this === 'function') {

throw new TypeError(`${this}.softBind is not a function`);

}

//#2 取参

const args = Array.prototype.shift.call(arguments) || [];

const fn = this;

//#3 定义函数,调用apply,此处注意对this的判断,改变新函数的原型

var softBindFn = function() {

return fn.apply((!this || this === (window || global) ? obj : this), [].concat(args, arguments));

}

softBindFn.prototype = fn.prototype;

return softBindFn;

}

复制代码

new的实现

new实现的过程:

创建一个新的对象

将新对象的隐式引用(proto)指向构造函数的原型

通过apply调用构造函数,给这个对象赋值

最后判断返回的对象是否是一个对象,然后结果

代码实现如下:

/**

* new模拟实现

*/

function myNew() {

//#1 创建一个空对象

let obj = Object.create({});

//#2 取出构造函数

let Constructor = Array.prototype.unshift.call(arguments);

//#3 改变新对象的隐式指向

obj._proto_ = Constructor.prototype;

//#4 调用构造函数,返回结果

ret = Constructor.apply(obj, arguments);

//#5 对结果进行判断

return ret instanceof Object ? ret : obj;

}

复制代码

instanceof的实现

instance的实现:

取出隐式引用(proto),然后和原型进行比较

依次往上循环,直到__proto__为null时

代码实现如下:

/**

* 实现instanceof

*/

function instanceFn(L, R) {

//#1 取出R的原型

const O = R.prototype;

//#2 取L的隐式指向,依次在原型链上判断

L = L._proto_;

while(true) {

if (L === null) {

//#3 当L为空时,返回false

return false;

} else {

//#4 当O与L相等是,说明继承于R

if (O === L) {

return true;

}

L = L._proto_;

}

}

}

复制代码

ES6的extend实现

ES6中的extend实现的原理:

将子构造函数的原型指向父构造函数的实例

然后改变原型中的构造函数(constructor)指向子构造函数

然后将子构造函数的隐式指向(proto)指向父构造函数

代码实现如下:

/**

* extend模拟实现

*/

function _inherits(subType, superType) {

//#1 创建对象,增强对象,指定对象

subType.prototype = Object.create(superType && superType.prototype, {

constructor: {

value: subType,

writable: true,

configurable: true,

enumerable: false

}

});

//#2 给子构造函数的隐式指向父构造函数

if (superType) {

Object.setPrototypeOf ? Object.setPrototypeOf(subType, superType) : subType._proto_ = superType;

}

}

复制代码

深拷贝和浅拷贝的实现

浅拷贝,就是只进行一层拷贝:

把对象的key取出来,然通过hasOwnProperty判断,赋值

深拷贝,就是无限层级的拷贝:

通过Map的形式,解决循环引用,如果对象存在,则直接返回

通过getOwnPropertySymbols的方法,解决Symbol值的拷贝

循环递归,拷贝对象属性

代码实现如下:

/**

* 浅拷贝

*/

function shallowCopy(obj) {

//#1 类型校验

if (obj !== 'object') return obj;

const target = {};

//#2 遍历对象的key

for (let key in obj) {

//#3 判断key是否在对象上

if (obj.hasOwnProperty(key)) {

target[key] === obj[key];

}

}

return target;

}

/**

* 深拷贝

*/

function isObject(obj) {

return typeof obj === 'object' && obj !== null;

}

function deepCopy(source, hash = new WeakMap()) {

//#1 类型校验

if (!isObject(source)) return source;

//#2 解决循环引用

if (hash.get(source)) return hash.get(source);

//#3 创建新对象,存入hash中

const target = Array.isArray(source) ? [] : {};

hash.set(source, target);

//#4 Symbol拷贝

const symbolArr = Object.getOwnPropertySymbols(source);

if (symbolArr.length) {

symbolArr.forEach(key => {

if (isObject(source[key])) {

target[key] = deepCopy(source[key], hash);

} else {

target[key] = source[key]

}

})

}

//#5 遍历对象key值

for (let key in source) {

//#6 判断是否是对象的key

if (source.hasOwnProperty(key)) {

//#7 判断属性类型

if (isObject(source[key])) {

target[key] = deepCopy(source[key], hash);

} else {

target[key] = source[key];

}

}

}

return target;

}

复制代码

防抖和节流的实现

节流:事件在一段时间内只会被触发一次,多次触发,只有一次生效

防抖:在事件触发n秒后再被调用,如果在这n秒内又被触发,则重新计时

代码实现如下:

/**

* 节流

*/

function throttle(fn, delay) {

//#1 定义上次触发时间

let last = 0;

return function() {

//#2 取参

const args = arguments;

const now = +new Date();

//#3 判断是否超过之前的时间

if (now < last + delay) {

last = now;

fn.apply(this, args);

}

};

}

/**

* 防抖

*/

function debounce(fn, delay) {

let timer;

return function(...args) {

//#1 判断定时器是否存在,清除定时器

if (timer) clearTimeout(timer);

//#2 重新调用setTimeout

timer = setTimeout(() => {

fn.apply(this, args);

}, delay);

};

}

复制代码

Promise的all和race实现

Promise.all:谁跑得慢,以谁为准,如果有一个失败,就返回失败结果

Promise.race:谁跑得快,以谁为准

代码实现如下:

/**

* all模拟实现

*/

Promise1.all = function (promises) {

//#1 计时器 & 结果数组

let count = 0;

const res = [];

//#2 传值函数,将结果放入结果数组

function processData (index, data, resolve) {

res[index] = data;

count++;

if (count === promises.length) {

resolve(res);

}

}

//#3 返回一个Promise

return new Promise((resolve, reject) => {

for (let j = 0; j < promises.length; j++) {

//#4 遍历promises数组,调用每个promise,将结果放入结果数组

promises[j].then(data => {

processData(j, data, resolve);

}, reject);

}

});

}

/**

* race模拟实现

*/

Promise1.race = function (promises) {

//#1 返回一个Promise

return new Promise((resolve, reject) => {

//#2 遍历promises数组,谁先返回,就用谁

for (let i = 0; i < promises.length; i++) {

promises[i].then(resolve, reject);

}

});

}

复制代码欢迎关注博主的微信公众号,我们一起做沟通和交流

银行java面试题手写代码_面试系列——手写代码实现(一)相关推荐

  1. java代码里的JSON格式怎么写好看_谁会不爱让代码骚里骚气的VSCode扩展插件呢?...

    点击上方 "Python人工智能技术" 关注,星标或者置顶22点24分准时推送,第一时间送达 来自:公众号 读芯术 | 编辑:真经君 码农真经(ID:coder_experienc ...

  2. 新网银行java面试题_新网银行面试

    有点累了.... 2017年9月13号下午四点半 ,去新网银行面试.这是我第一次参加群面(但当时是两个人一组进行面试,所以我和另外一个哥们一起面对两个面试官回答问题),有点紧张,导致手写代码和回答问题 ...

  3. java基础试题_java基础测试题_含答案.doc

    java基础测试题_含答案 Java基础试题 姓名 一.选择题(每题2分,共30分) 请写出标识符的命名规则描述正确的是[多选]( ABCD ) A.由英文字母.数字._和$组成,长度不限. B.标识 ...

  4. idea看更改过的代码_就是你把所有代码全写在一个类里的?

    来源 | https://urlify.cn/6jQRN3 最近,在对已有项目进行扩展的时候,发现要改动的一个类它长900行,开放了近40个public接口,我流着泪把它给改完了. 为了防止这样的惨剧 ...

  5. 微信小程序 手写签名_小程序手写签名(wepy)

    对于手写签名组件组件晚上有很多种写法,我选择了一种进行了wepy的框架的改造.如果使用wepy框架做手写签名的话可以直接复制下面的代码. 这里需要提醒的是:安卓手机和苹果手机有适配性的问题,苹果手机在 ...

  6. java词频统计简单带代码_简单的词频统计代码实现(PDF格式)

    周末抽空帮同学论文写了一段统计词频的代码,做个简单总结.出于职业病,代码使用Springboot+Maven搭建,面向抽象编程,并通过web请求控制执行. 依赖配置 org.springframewo ...

  7. vue 手写签名_与众不同的手写签批

    随着移动互联网+时代的到来,手机成了我们日常生活中不可缺少的必备用品,它不仅仅是一个通讯工具,更是一台移动电脑.因此越来越多的单位把希望在手机上就能完成业务的处理,但也希望能还原线下办理的效果.因此, ...

  8. python笔记手写照片_用Python对手写笔记进行压缩与增强

    Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发. 我写了一个程序来清洁手写笔记的扫描图,并同时减少文件大小. 示例输入输出: 左边: 300 DPI, 7. ...

  9. python写词法分析器_如何用python写一个简单的词法分析器

    编译原理老师要求写一个java的词法分析器,想了想决定用python写一个. 目标 能识别出变量,数字,运算符,界符和关键字,用excel表打印出来. 有了目标,想想要怎么实现词法分析器. 1.先进行 ...

最新文章

  1. canny边缘检测 关于2个阈值参数
  2. 凭啥Java运行环境称虚拟机 Python只能称解释器
  3. 如何快速搭建一个简约美观的在线互动教室?
  4. 深入理解Spring AOP思想
  5. C++多态案例二-制作饮品
  6. python安装环境傻瓜式安装_前后端分离——前端开发环境傻瓜式一步到位 nodejs ruby python nginx 安装搭建配置...
  7. spring aop的两种写法aspect和advisor
  8. CaseStudy-数据缓存出错
  9. 遇到的坑_那些年跟团游遇到的坑,花了很多钱才发现自己被坑了
  10. socket 函数 setsockopt()用法
  11. 第一章:网络信息安全概述精讲笔记
  12. Marlin代码分析一些记录
  13. 嵌入式系统课程大作业设计报告
  14. 数据可视化之使用Matplotlib绘制甘特图
  15. java pdf转图片base64,itextpdf 实现html转pdf中中文及图片base64的解决方法
  16. python直角坐标转极坐标_Python在OpenCV里实现极坐标变换功能
  17. 4.3.用python解決經典問題:生日悖論, birthday paradox
  18. 只用3行代码,让Python提速4倍!最强辅助
  19. 时间序列分析中resample函数
  20. 表格式计算机教案模板,教案的表格格式_教案的表格模板

热门文章

  1. js 实现精准定位(使用百度地图API)
  2. java从服务器读取文件_Java从服务器读取文件并下载到本地
  3. 二十四、Gtk4-GtkExpression
  4. Bitmap实现照片墙
  5. 苏宁易购双十一搞了一场“三无”发布会,却被称赞“干货满满”
  6. 陌陌开始发力直播,它和那些竞品们有何不同?
  7. 无法进入netsarang官网
  8. 图像识别之字符识别方法
  9. requestPermissions读写手机存储权限_Android 11 开发者常见问题:存储|FAQ?第二期
  10. 迅雷看看的带宽限制 是不能限制 还是不想限制?