一、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常用的函数的更多相关文章

  1. 第三节,TensorFlow 使用CNN实现手写数字识别(卷积函数tf.nn.convd介绍)

    上一节,我们已经讲解了使用全连接网络实现手写数字识别,其正确率大概能达到98%,这一节我们使用卷积神经网络来实现手写数字识别, 其准确率可以超过99%,程序主要包括以下几块内容 [1]: 导入数据,即 ...

  2. javascript常用字符串函数和本地存储

    concat将两个或多个字符的文本组合起来,返回一个新的字符串.var a = "hello";var b = ",world";var c = a.conca ...

  3. javascript常用工具函数总结(不定期补充)未指定标题的文章

    前言 以下代码来自:自己写的.工作项目框架上用到的.其他框架源码上的.网上看到的. 主要是作为工具函数,服务于框架业务,自身不依赖于其他框架类库,部分使用到es6/es7的语法使用时要注意转码 虽然尽 ...

  4. 一起手写吧!sleep函数!

    Async/Await 版本 function sleep(delay) { return new Promise(reslove => { setTimeout(reslove, delay) ...

  5. JavaScript常用工具函数

    检测数据是不是除了symbol外的原始数据 function isStatic(value) { return ( typeof value === 'string' || typeof value ...

  6. javascript 常用实用函数。。。。。。

    javascript 正则表达式 1.获取屏幕大小尺寸 /* 获取屏幕大小尺寸 */ var getScreen = function () { var screen = { width: 0, he ...

  7. JavaScript 常用数组函数方法专题

    1. 由字符串生成数组 split() 分割字符串,并将分割的部分作为一个元素保存在一个新建的数组中. var str1 = "this is an emample to using the ...

  8. javascript常用功能函数

    特殊字符转义:将<, >, &, “进行转义 function escape(str){ return str.replace(/[<>"&]/g,f ...

  9. JavaScript数组方法总结及手写

    目录 手写数组衍生方法 1.检测是否为数组 2.类数组转化为数组 3.数组扁平化 4.数组去重 5.数组使用Math.max 手写数组内置方法 1. Array.prototype.filter 2. ...

随机推荐

  1. .NET使用gRPC

    gRPC 简单介绍: grpc 是一个高性能.开源和通用的 RPC 框架,面向移动和 HTTP/2 设计.目前提供 C.Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc ...

  2. Google Colab Free GPU Tutorial【转载】

    转自:https://medium.com/deep-learning-turkey/google-colab-free-gpu-tutorial-e113627b9f5d 1.Google Cola ...

  3. Vue 读取Excel数据

    参考:https://my.oschina.net/u/3720342/blog/1838063 参考2:https://www.cnblogs.com/liguiwang/p/8430672.htm ...

  4. ssl证书 以及phpstudy配置ssl证书

    首先,确保你的Apache编译了SSL模块,这是支持SSL证书必要的条件(如果没有,请编译,[打开phpstudy]>[其他选项菜单]>[PHP扩展]>[php-openssl]前面 ...

  5. C# 数组在内存中的存储

    C# 数组是引用类型,那么在内存中是如何存储的呢? 在VS中调试C#程序,如何查看内存.寄存器.反汇编 在这篇文章里看到了如何在VS 中查看内存 先断点打在数组创建后语句那里,点debug->W ...

  6. windows之电脑开机出现 this product is covered by one or more of the following prtents

    电脑开机出现 this product is covered by one or more of the following prtents 有次意外断电后就每次都出现这个提示,然后要等检查完才能进入 ...

  7. 通过js或jq增加的代码,点击事件或其他一些事件不起作用时

    通过js或jq增加的代码,点击事件或其他一些事件不起作用时,可使用 $(document).on("click",".noshow",function() { ...

  8. 目标检测方法——R-FCN

    R-FCN论文阅读(R-FCN: Object Detection via Region-based Fully Convolutional Networks ) 目录 作者及相关链接 方法概括 方法 ...

  9. Web应用启动时,后台自动启动一个线程(转)

    原文:http://blog.sina.com.cn/s/blog_6810dfc20101ipzq.html Web应用启动时,后台自动启动一个线程 (1)前言 前几天,manager问道一个问题: ...

  10. ajax 防止重复提交

    参考链接:http://www.hollischuang.com/archives/931 http://blog.csdn.net/everything1209/article/details/52 ...