一些手寫(xiě)JavaScript常用的函數(shù)匯總
前言
在JavaScript中,幾乎每次編寫(xiě)一段代碼時(shí),通常都會(huì)寫(xiě)入一個(gè)函數(shù)。我們的大部分代碼執(zhí)行都是函數(shù)調(diào)用的結(jié)果。所以本文主要給大家介紹了一些JavaScript常用的函數(shù),下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧
JavaScript常用的函數(shù)
一、bind、call、apply函數(shù)的實(shí)現(xiàn)改變函數(shù)的執(zhí)行上下文中的this指向,但不執(zhí)行該函數(shù)(位于Function構(gòu)造函數(shù)的原型對(duì)象上的方法)
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
}
二、引用數(shù)據(jù)類型的深拷貝方法的實(shí)現(xiàn)
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
}
//遞歸遍歷對(duì)象或數(shù)組中的屬性值或元素為原始值為止
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
}
思路:
- 輸入需要深拷貝的目標(biāo)target,輸出深拷貝后的結(jié)果
- 通過(guò)Object.prototype.toString準(zhǔn)確判斷傳入的目標(biāo)target的數(shù)據(jù)類型,當(dāng)target的數(shù)據(jù)類型為對(duì)象或者數(shù)組時(shí),會(huì)對(duì)target進(jìn)行遞歸遍歷直至當(dāng)遍歷的數(shù)組或者對(duì)象中的數(shù)據(jù)全部為基本數(shù)據(jù)類型為止
三、數(shù)組flat函數(shù)的實(shí)現(xiàn)
Array.prototype.flat
四、實(shí)現(xiàn)n的階乘
分析:首先找規(guī)律,舉例如3的階乘等于3*2*1,也就是等于n*n-1*n-2的階乘,也就是等于3*2*1的階乘,計(jì)算到1的階乘之后,整個(gè)計(jì)算過(guò)程才結(jié)束。分析到很容易想到通過(guò)遞歸來(lái)實(shí)現(xiàn)這個(gè)數(shù)的階乘,因?yàn)榈谝?,這個(gè)計(jì)算過(guò)程有規(guī)律可循,第二它有最終停止計(jì)算的出口,也就是當(dāng)計(jì)算到1的時(shí)候就停止運(yùn)算,以下通過(guò)遞歸來(lái)實(shí)現(xiàn)
function factorial (num) {
if (num < 0) {
throw new Error('負(fù)數(shù)沒(méi)有階乘')
}
if (num === 1 || num === 0) {
return 1
}
return num * factorial(num-1)
}
factorial(3) //6
五、實(shí)現(xiàn)斐波拉契數(shù)列
分析:按照上述階乘的分析過(guò)程分析,這里不贅述
function fibonacci (n) {
//此方法應(yīng)使用尾遞歸法進(jìn)行優(yōu)化,這里不作優(yōu)化,簡(jiǎn)單實(shí)現(xiàn)
if ( n <= 1 ) {return 1};
return fibonacci(n - 1) + fibonacci(n - 2);}
六、實(shí)現(xiàn)一個(gè)計(jì)算字符串字節(jié)長(zhǎng)度的函數(shù)
分析:首先我們要知道英文的字節(jié)長(zhǎng)度是1,而中文的字節(jié)長(zhǎng)度是2,但是如何判斷當(dāng)前字符位是漢字還是英文呢,通過(guò)charCodeAt來(lái)判斷當(dāng)前字符位的unicode編碼是否大于255,如何大于255則是漢字,那就給字符串的字節(jié)長(zhǎng)度加2,如果小于255則是英文,就給字符串的字節(jié)長(zhǎng)度加1,以下按照這個(gè)思路實(shí)現(xiàn)
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
七、實(shí)現(xiàn)isNaN函數(shù)
分析:要判斷傳入的值是否是"is not a number"(isNaN全拼),首先進(jìn)行一個(gè)數(shù)字的隱式類型轉(zhuǎn)換,通過(guò)Number包裝類來(lái)實(shí)現(xiàn)Number(x),再判斷Numberz(x)的返回值是否是NaN,如果是的話再與NaN進(jìn)行比對(duì),但是由于NaN雖然是number類型的,但是是不能進(jìn)行比較的,所以我們先將Number(x)返回的結(jié)果變成字符串形式,再去判斷,實(shí)現(xiàn)如下
function isNaN(num) {
var ret = Number(num)
ret += ''
if (ret === 'NaN') {
return true
}
return false
}
isNaN('123abc') // true
八、實(shí)現(xiàn)數(shù)組的push函數(shù)
分析:首先push函數(shù)是位于Array構(gòu)造函數(shù)的原型對(duì)象上的方法,所以要在Array.prototype上去定義,然后再分析push函數(shù)的作用是往數(shù)組的末尾添加元素,可以添加任意個(gè)數(shù)的元素,并且最終返回?cái)?shù)組的長(zhǎng)度,實(shí)現(xiàn)代碼如下
Array.prototype.push = function () {
for (var i = 0; i< arguments.length; i++) {
this[this.length] = arguments[i]
}
return this.length
}
七、實(shí)現(xiàn)能夠識(shí)別所有數(shù)據(jù)類型的typeof分
析:首先typeof是位于window對(duì)象上的全局方法,所以我們定義完成之后要將其掛載到window上,其次要實(shí)現(xiàn)識(shí)別所有數(shù)據(jù)類型包括:基本數(shù)據(jù)類型和復(fù)雜數(shù)據(jù)類型(引用數(shù)據(jù)類型),我們需要通過(guò)Object.prototype.toString方法去做才唯一能夠最準(zhǔn)確判斷當(dāng)前值為什么數(shù)據(jù)類型,實(shí)現(xiàn)代碼如下
window.typeof = function (value) {
return Object.prototype.toString.call(val).slice(8, -1)
}
八、實(shí)現(xiàn)數(shù)組的去重方法
分析:首先因?yàn)槭墙o所有數(shù)組實(shí)例實(shí)現(xiàn)一個(gè)去重方法,所以同樣是在原型鏈上進(jìn)行編程
Array.prototype.unique = function () {
//這里是利用對(duì)象鍵hash值的唯一性來(lái)去重
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) //生成一個(gè)類數(shù)組
return Array.from(result) //通過(guò)Array.from將類數(shù)組轉(zhuǎn)換成真正的數(shù)組
}
Array.prototype.unique = function () {
//利用Array.prototype.filter返回符合條件的元素
//利用Array.prototype.indexOf返回?cái)?shù)組中第一次出現(xiàn)當(dāng)前元素的索引值
//該方法寫(xiě)法最為優(yōu)雅,一行代碼搞定,函數(shù)式編程
return this.filter((item, index) => this.indexOf(item) === index)
}
九、實(shí)現(xiàn)函數(shù)的防抖、節(jié)流
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)
}
}
}
十一、實(shí)現(xiàn)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、原型鏈繼承:子類型的原型對(duì)象為父類型的實(shí)例對(duì)象
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、借用構(gòu)造函數(shù)實(shí)現(xiàn)繼承:在子類的構(gòu)造函數(shù)中通過(guò)call調(diào)用父類的構(gòu)造函數(shù)實(shí)現(xiàn)繼承
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、原型鏈+借用構(gòu)造函數(shù)的組合繼承方式:通過(guò)在子類構(gòu)造函數(shù)中通過(guò)call調(diào)用父類構(gòu)造函數(shù),繼承父類的屬性并保留傳參的優(yōu)點(diǎn),再通過(guò)將父類的實(shí)例作為子類的原型對(duì)象,實(shí)現(xiàn)繼承
function Person (name, age) {
this.name = name
this.age = age
}
Person
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
- javascript 星級(jí)評(píng)分效果(手寫(xiě))
- 純JavaScript手寫(xiě)圖片輪播代碼
- Angularjs 手寫(xiě)日歷的實(shí)現(xiàn)代碼(不用插件)
- JS實(shí)現(xiàn)手寫(xiě)parseInt的方法示例
- 自己動(dòng)手寫(xiě)的javascript前端等待控件
- JS手寫(xiě)一個(gè)自定義Promise操作示例
- JS實(shí)現(xiàn)手寫(xiě) forEach算法示例
- 如何從零開(kāi)始利用js手寫(xiě)一個(gè)Promise庫(kù)詳解
- JavaScript常見(jiàn)手寫(xiě)題超全匯總
相關(guān)文章
JavaScript 監(jiān)聽(tīng)textarea中按鍵事件
不同的瀏覽器中的事件監(jiān)聽(tīng)機(jī)制是不同的,以onKeyPress事件為例。2009-10-10
javascript setAttribute, getAttribute 在不同瀏覽器上的不同表現(xiàn)
該方法把指定的屬性設(shè)置為指定的值。如果不存在具有指定名稱的屬性,該方法將創(chuàng)建一個(gè)新屬性。2010-08-08
純JavaScript實(shí)現(xiàn)猜數(shù)字游戲
這篇文章主要為大家詳細(xì)介紹了純JavaScript實(shí)現(xiàn)猜數(shù)字游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
JS實(shí)現(xiàn)滑動(dòng)菜單效果代碼(包括Tab,選項(xiàng)卡,橫向等效果)
這篇文章主要介紹了JS實(shí)現(xiàn)滑動(dòng)菜單效果代碼,以實(shí)例形式實(shí)現(xiàn)了包括Tab,選項(xiàng)卡,橫向等效果,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-09-09
在IE下獲取object(ActiveX)的Param的代碼
在IE下,獲取Param的時(shí)候有個(gè)詭異現(xiàn)象(不知道算不算bug)。2009-09-09
JS+CSS實(shí)現(xiàn)滾動(dòng)數(shù)字時(shí)鐘效果
本篇文章教給大家用JS代碼配合CSS樣式來(lái)實(shí)現(xiàn)滾動(dòng)時(shí)鐘的動(dòng)畫(huà)效果,一起來(lái)學(xué)習(xí)下。2017-12-12

