一些手写JavaScript常用的函数汇总


Posted in Javascript onApril 16, 2019

前言

在JavaScript中,几乎每次编写一段代码时,通常都会写入一个函数。我们的大部分代码执行都是函数调用的结果。所以本文主要给大家介绍了一些JavaScript常用的函数,下面话不多说了,来一起看看详细的介绍吧

JavaScript常用的函数

一、bind、call、apply函数的实现改变函数的执行上下文中的this指向,但不执行该函数(位于Function构造函数的原型对象上的方法)

Function.prototype.myBind = function (target) {
 if (typeof this !== 'function') {
 throw Error('myBind is not a function')
 }
 var that = this
 var args1 = [...arguments].slice(1)
 var func = function () {
 var args2 = [..arguments].slice(1)
 return that.apply(target || window, args1.concat(args2)) }
 return func
}

Function.prototype.myCall = function (context=window) {
 if (typeof this !== 'function') {
 throw Error('myBind is not a function') 
 } 
 context.fn = this
 var args = [...arguments].slice(1)
 var result = context.fn(..args) 
 delete context.fn
 return result                                                  
}

Function.prototype.myApply = function (context=window) {
 if (typeof this !== 'function') {
 throw Error('myApply is not a function')
 }
 context.fn = this
 var result
 if (argument[1]) {
 result = context.fn(...arguments[1])
 } else {
 result = context.fn()
 }
 delete context.fn
 return result
}

二、引用数据类型的深拷贝方法的实现

function cloneDeep (target) {
 function checkType(target) {
 return Object.prototype.toString.call(target).slice(8, -1)
 }
 var result, checkedType = checkType(target)
 if (checkedType === 'Array') {
 result = []
 } else if (checkedType === 'Object') {
 result = {}
 } else {
 return target
 }
 //递归遍历对象或数组中的属性值或元素为原始值为止
 for (var key in target) {
 if ( checkType(target[key]) === 'Array' || checkType(target[key]) === 'Object') {
  result[key] = cloneDeep(target[key])
 } else {
  result[key] = target[key]
 }
 }
 return result
}

思路:

  • 输入需要深拷贝的目标target,输出深拷贝后的结果
  • 通过Object.prototype.toString准确判断传入的目标target的数据类型,当target的数据类型为对象或者数组时,会对target进行递归遍历直至当遍历的数组或者对象中的数据全部为基本数据类型为止

三、数组flat函数的实现

Array.prototype.flat

四、实现n的阶乘

分析:首先找规律,举例如3的阶乘等于3*2*1,也就是等于n*n-1*n-2的阶乘,也就是等于3*2*1的阶乘,计算到1的阶乘之后,整个计算过程才结束。分析到很容易想到通过递归来实现这个数的阶乘,因为第一,这个计算过程有规律可循,第二它有最终停止计算的出口,也就是当计算到1的时候就停止运算,以下通过递归来实现

function factorial (num) {
 if (num < 0) {
 throw new Error('负数没有阶乘')
 }
 if (num === 1 || num === 0) {
 return 1
 }
 return num * factorial(num-1)
}

factorial(3) //6

五、实现斐波拉契数列

分析:按照上述阶乘的分析过程分析,这里不赘述

function fibonacci (n) {
 //此方法应使用尾递归法进行优化,这里不作优化,简单实现
 if ( n <= 1 ) {return 1};
 return fibonacci(n - 1) + fibonacci(n - 2);}

六、实现一个计算字符串字节长度的函数

分析:首先我们要知道英文的字节长度是1,而中文的字节长度是2,但是如何判断当前字符位是汉字还是英文呢,通过charCodeAt来判断当前字符位的unicode编码是否大于255,如何大于255则是汉字,那就给字符串的字节长度加2,如果小于255则是英文,就给字符串的字节长度加1,以下按照这个思路实现

function countBytesLength(str){
 var length = 0
 //首先遍历传入的字符串
 for(var i = 0; i < str.length; i++) {
  if (str[i].charCodeAt(i) > 255) {
   length += 2
  } else {
   length++
  }
 }
  return length
}

var str = 'DBCDouble陈'
countBytesLength(str) //11

七、实现isNaN函数

分析:要判断传入的值是否是"is not a number"(isNaN全拼),首先进行一个数字的隐式类型转换,通过Number包装类来实现Number(x),再判断Numberz(x)的返回值是否是NaN,如果是的话再与NaN进行比对,但是由于NaN虽然是number类型的,但是是不能进行比较的,所以我们先将Number(x)返回的结果变成字符串形式,再去判断,实现如下

function isNaN(num) {
 var ret = Number(num)
 ret += ''
 if (ret === 'NaN') {
  return true
 }
 return false
} 
isNaN('123abc') // true

八、实现数组的push函数

分析:首先push函数是位于Array构造函数的原型对象上的方法,所以要在Array.prototype上去定义,然后再分析push函数的作用是往数组的末尾添加元素,可以添加任意个数的元素,并且最终返回数组的长度,实现代码如下

Array.prototype.push = function () {
 for (var i = 0; i< arguments.length; i++) {
  this[this.length] = arguments[i]
 }
 return this.length
}

七、实现能够识别所有数据类型的typeof分

析:首先typeof是位于window对象上的全局方法,所以我们定义完成之后要将其挂载到window上,其次要实现识别所有数据类型包括:基本数据类型和复杂数据类型(引用数据类型),我们需要通过Object.prototype.toString方法去做才唯一能够最准确判断当前值为什么数据类型,实现代码如下

window.typeof = function (value) {
 return Object.prototype.toString.call(val).slice(8, -1)
}

八、实现数组的去重方法

分析:首先因为是给所有数组实例实现一个去重方法,所以同样是在原型链上进行编程

Array.prototype.unique = function () {
 //这里是利用对象键hash值的唯一性来去重
 var obj = {}
 var result = []
 for (var i = 0; i < this.length; i++) {
  if (!obj[this[i]]) {
   obj[this[i]] = true
   result.push(this[i])
  }
 }
 return result
}

var arr = [1,2,2,3,3]
arr.unique() //[1,2,3]
Array.prototype.unique = function () {
 //利用ES6的Array.prototype.includes
 var result = []
 for (var i = 0; i < this.length; i++) {
  if (!result.includes(this[i])) {
   result.push(this[i])
  }
 }
 return result
}
Array.prototype.unique = function () {
 //利用ES6的Set
 var result = new Set(this) //生成一个类数组
 return Array.from(result) //通过Array.from将类数组转换成真正的数组
}
Array.prototype.unique = function () {
 //利用Array.prototype.filter返回符合条件的元素
 //利用Array.prototype.indexOf返回数组中第一次出现当前元素的索引值
 //该方法写法最为优雅,一行代码搞定,函数式编程
 return this.filter((item, index) => this.indexOf(item) === index)
}

九、实现函数的防抖、节流

function debounce (fn, wait=300) {
 var timer
 return function () {
  if (timer) {
   clearTimeOut(timer)
  }
  timer = setTimeout({
   fn.apply(this, arguments) 
  }, wait)
 }
}

function throttle (fn, wait=300) {
 var prev = +new Date()
 return function () {
  var now = +new Date()
  if (prev - now > 300) {
   fn.apply(this, arguments)
   prev = now
  }
 }
}

十、封装ajax

function ajax (options) {
 options = options || {}
 options.url = options.url || ''
 options.method = options.method.toUpperCase() || 'GET'
 options.async = options.async || true
 options.data = options.data || null
 options.success = options.success || function () {}
 var xhr = null 
 if (XMLHttpRequest) {
  xhr = new XMLHttpRequest()
 } else {
  xhr = new ActiveXObject('Microsoft.XMLHTTP')
 }
 xhr.open(options.url, options.method, options.async)
 var postData = []
 for (var key in options.data) {
  postData.push(key + '='+ options.data[key])
 }
 if (options.method === 'POST') {
  xhr.open(options.method, options.url, options.async )
  xhr.send(postData)
 } else if (options.method === 'GET') {
  xhr.open(options.mehtod, options.url + postData.join('&'), options.async)
  xhr.send(null)
 }
 xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && xhr.status === 200) {
   options.success(xhr.responseText)
  }
 }
}

十一、实现new操作符

function ajax (options) {
 options = options || {}
 options.url = options.url || ''
 options.method = options.method.toUpperCase() || 'GET'
 options.async = options.async || true
 options.data = options.data || null
 options.success = options.success || function () {}
 var xhr = null 
 if (XMLHttpRequest) {
  xhr = new XMLHttpRequest()
 } else {
  xhr = new ActiveXObject('Microsoft.XMLHTTP')
 }
 xhr.open(options.url, options.method, options.async)
 var postData = []
 for (var key in options.data) {
  postData.push(key + '='+ options.data[key])
 }
 if (options.method === 'POST') {
  xhr.open(options.method, options.url, options.async )
  xhr.send(postData)
 } else if (options.method === 'GET') {
  xhr.open(options.mehtod, options.url + postData.join('&'), options.async)
  xhr.send(null)
 }
 xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && xhr.status === 200) {
   options.success(xhr.responseText)
  }
 }
}

十二、常用六种继承方式

1、原型链继承:子类型的原型对象为父类型的实例对象

function Person (name, age) {
 this.name = name 
 this.age = age
}

Person.prototype.setName = function () {
 console.log(this.name)
}

function Student (height) {
 this.height = height
}

Student.prototype = new Person()
var stu = new Student('175')
console.log(stu)

2、借用构造函数实现继承:在子类的构造函数中通过call调用父类的构造函数实现继承

function Person (name, age) {
 this.name = name 
 this.age = age
}

Person.prototype.setName = function () {
 console.log(this.name)
}

function Student (height, age, name) {
 Person.call(this, age, name)
 this.height = height
}

var stu = new Studeng(175, 'cs', 24)
console.log(stu)

3、原型链+借用构造函数的组合继承方式:通过在子类构造函数中通过call调用父类构造函数,继承父类的属性并保留传参的优点,再通过将父类的实例作为子类的原型对象,实现继承

function Person (name, age) {
 this.name = name 
 this.age = age
}

Person

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
基于jquery实现的类似百度搜索的输入框自动完成功能
Aug 23 Javascript
js利用prototype调用Array的slice方法示例
Jun 09 Javascript
javascript制作坦克大战全纪录(2)
Nov 27 Javascript
jQuery实现列表的全选功能
Mar 18 Javascript
js实现tab切换效果实例
Sep 16 Javascript
jquery中ajax处理跨域的三大方式
Jan 05 Javascript
js实现打地鼠小游戏
Feb 13 Javascript
Vue.js tab实现选项卡切换
May 16 Javascript
JS中跳出循环的示例代码
Sep 14 Javascript
解决Vue-cli npm run build生产环境打包,本地不能打开的问题
Sep 20 Javascript
vue+express+jwt持久化登录的方法
Jun 14 Javascript
vue iview 隐藏Table组件里的某一列操作
Nov 13 Javascript
浏览器事件循环与vue nextTicket的实现
Apr 16 #Javascript
理理Vue细节(推荐)
Apr 16 #Javascript
ES6知识点整理之Proxy的应用实例详解
Apr 16 #Javascript
js实现删除li标签一行内容
Apr 16 #Javascript
js实现弹出框的拖拽效果实例代码详解
Apr 16 #Javascript
重学 JS:为啥 await 不能用在 forEach 中详解
Apr 15 #Javascript
你不知道的Vue技巧之--开发一个可以通过方法调用的组件(推荐)
Apr 15 #Javascript
You might like
追忆往昔!浅谈收音机的百年发展历史
2021/03/01 无线电
PHP中批量生成静态html(命令行下运行PHP)
2014/04/19 PHP
jQuery调用WebService的实现代码
2011/06/19 Javascript
40个有创意的jQuery图片和内容滑动及弹出插件收藏集之二
2011/12/31 Javascript
常用的JS验证和函数汇总
2014/12/23 Javascript
JavaScript控制图片加载完成后调用回调函数的方法
2015/03/20 Javascript
Nodejs实现批量下载妹纸图
2015/05/28 NodeJs
基于Jquery easyui 选中特定的tab
2015/11/17 Javascript
AngularJs表单验证实例详解
2016/05/30 Javascript
教你JS中的运算符乘方、开方及变量格式转换
2016/08/09 Javascript
jquery UI Datepicker时间控件冲突问题解决
2016/12/16 Javascript
微信小程序 五星评分的实现实例
2017/08/04 Javascript
jQuery中将json数据显示到页面表格的方法
2018/05/27 jQuery
实例分析vue循环列表动态数据的处理方法
2018/09/28 Javascript
解决vue使用vant下拉框van-dropdown-item 绑定title值不变问题
2020/08/05 Javascript
[36:16]完美世界DOTA2联赛PWL S3 access vs Rebirth 第一场 12.19
2020/12/24 DOTA
python使用xauth方式登录饭否网然后发消息
2014/04/11 Python
Python实现3行代码解简单的一元一次方程
2014/08/18 Python
Windows上配置Emacs来开发Python及用Python扩展Emacs
2015/11/20 Python
pandas 选择某几列的方法
2018/07/03 Python
pip安装py_zipkin时提示的SSL问题对应
2018/12/29 Python
python tkinter实现彩球碰撞屏保
2019/07/30 Python
浅谈python3打包与拆包在函数的应用详解
2020/05/02 Python
使用pygame实现垃圾分类小游戏功能(已获校级二等奖)
2020/07/23 Python
python 视频下载神器(you-get)的具体使用
2021/01/06 Python
Python读取pdf表格写入excel的方法
2021/01/22 Python
英国花园、DIY、电器和家居用品商店:Robert Dyas
2019/03/18 全球购物
全球领先的中国制造商品在线批发平台:DHgate
2020/01/28 全球购物
美国沃尔玛网上超市:Walmart
2020/08/14 全球购物
const char*, char const*, char*const的区别是什么
2014/07/09 面试题
安全教育心得体会
2013/12/29 职场文书
财务内勤岗位职责
2014/04/17 职场文书
一年级学生期末评语
2014/04/21 职场文书
团队拓展活动方案
2014/08/28 职场文书
批评与自我批评范文
2014/10/15 职场文书
sql查询结果列拼接成逗号分隔的字符串方法
2021/05/25 SQL Server