手写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) //
五、实现斐波拉契数列
分析:按照上述阶乘的分析过程分析,这里不赘述
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) //
七、实现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 new (fn) {
return function () {
var obj = {
'__proto__': fn.prototype
}
fn.apply(obj, arguments)
return obj
}
}
十二、常用六种继承方式
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
作者:DBCdouble
链接:https://juejin.im/post/5c6cfded518825655917261d
手写JavaScript常用的函数的更多相关文章
- 第三节,TensorFlow 使用CNN实现手写数字识别(卷积函数tf.nn.convd介绍)
上一节,我们已经讲解了使用全连接网络实现手写数字识别,其正确率大概能达到98%,这一节我们使用卷积神经网络来实现手写数字识别, 其准确率可以超过99%,程序主要包括以下几块内容 [1]: 导入数据,即 ...
- javascript常用字符串函数和本地存储
concat将两个或多个字符的文本组合起来,返回一个新的字符串.var a = "hello";var b = ",world";var c = a.conca ...
- javascript常用工具函数总结(不定期补充)未指定标题的文章
前言 以下代码来自:自己写的.工作项目框架上用到的.其他框架源码上的.网上看到的. 主要是作为工具函数,服务于框架业务,自身不依赖于其他框架类库,部分使用到es6/es7的语法使用时要注意转码 虽然尽 ...
- 一起手写吧!sleep函数!
Async/Await 版本 function sleep(delay) { return new Promise(reslove => { setTimeout(reslove, delay) ...
- JavaScript常用工具函数
检测数据是不是除了symbol外的原始数据 function isStatic(value) { return ( typeof value === 'string' || typeof value ...
- javascript 常用实用函数。。。。。。
javascript 正则表达式 1.获取屏幕大小尺寸 /* 获取屏幕大小尺寸 */ var getScreen = function () { var screen = { width: 0, he ...
- JavaScript 常用数组函数方法专题
1. 由字符串生成数组 split() 分割字符串,并将分割的部分作为一个元素保存在一个新建的数组中. var str1 = "this is an emample to using the ...
- javascript常用功能函数
特殊字符转义:将<, >, &, “进行转义 function escape(str){ return str.replace(/[<>"&]/g,f ...
- JavaScript数组方法总结及手写
目录 手写数组衍生方法 1.检测是否为数组 2.类数组转化为数组 3.数组扁平化 4.数组去重 5.数组使用Math.max 手写数组内置方法 1. Array.prototype.filter 2. ...
随机推荐
- TCP/IP协议 网络层
IP协议介绍 1.IP协议是TCP/IP协议族中最为核心的协议.IP协议将多个包交换网络连接起来,它在源地址和目的地址之间传送一种称为数据包的东西,它还提供对数据大小的重新组装功能,以适应不同网络对包 ...
- vi检索
/ :检索 n :向下执行上一步的检索 N :向上执行上一步的检索
- 2018-2019-2 网络对抗技术 20165321 Exp6 信息搜集与漏洞扫描
1.实践目标 掌握信息搜集的最基础技能与常用工具的使用方法. 2.实践内容 (1)各种搜索技巧的应用 百度查找IP地址: 查了一下kali的IP地址 https://fofa.so/的使用: 查询了一 ...
- python模块学习之hashlib模块学习
# 加密模块 import hashlib # md5 加密 md5 # 1.初始化md5模块 生成md5对象 # 2.引入要加密的数据 update # 3.获取加密值 hexdigest m = ...
- 运行main方法找不到类
http://blog.csdn.net/chenleixing/article/details/44816629
- eclipse中使用workset整理项目
eclipse项目过多怎么方便管理呢? 可以使用workset来进行管理.这里的workset跟.net 也就是visual studio中的项目解决方法类似,可以将项目.类库进行分开管理. 可以点击 ...
- P3974 [TJOI2015]组合数学
题目描述 为了提高智商,ZJY开始学习组合数学.某一天她解决了这样一个问题:给一个网格图,其中某些格子有财宝.每次从左上角出发,只能往右或下走.问至少要走几次才可能把财宝全捡完. 但是她还不知足,想到 ...
- Python 第八阶段 学习记录之---算法
算法(Algorithm): 一个计算过程, 解决问题的方法 1.递归的两个特点 - 调用自身 - 结束条件 时间复杂度 - 时间复杂度是用来估计算法运行时间的一个式子(单位) - 一般来说,时间复杂 ...
- java 几个实用的小工具
1.除法运算 编程的人都知道,java中的“/”.“%”运算,其中前者为取整,后者取余数.那么有没有快捷的运算方法取正常的运算结果呢? 查了资料,发现很简单.代码如下: public static S ...
- webservice接口的开发和调用
一.WebService的开发手段 使用Java开发WebService时可以使用以下两种开发手段 1. 使用JDK开发(1.6及以上版本) 2.使用CXF框架开发(工作中) 二.使用JDK开发Web ...