前言
在JavaScript中,几乎每次编写一段代码时,通常都会写入一个函数。我们的大部分代码执行都是函数调用的结果。所以本文主要给大家介绍了一些JavaScript常用的函数,下面话不多说了,来一起看看详细的介绍吧
JavaScript常用的函数
一、bind、call、apply函数的实现改变函数的执行上下文中的this指向,但不执行该函数(位于Function构造函数的原型对象上的方法)
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
}
二、引用数据类型的深拷贝方法的实现
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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函数的实现
?
四、实现n的阶乘
分析:首先找规律,举例如3的阶乘等于3*2*1,也就是等于n*n-1*n-2的阶乘,也就是等于3*2*1的阶乘,计算到1的阶乘之后,整个计算过程才结束。分析到很容易想到通过递归来实现这个数的阶乘,因为第一,这个计算过程有规律可循,第二它有最终停止计算的出口,也就是当计算到1的时候就停止运算,以下通过递归来实现
?
1
2
3
4
5
6
7
8
9
10
11
function
factorial (num) {
if
(num < 0) {
throw
new
Error(
'负数没有阶乘'
)
}
if
(num === 1 || num === 0) {
return
1
}
return
num * factorial(num-1)
}
factorial(3)
//6
五、实现斐波拉契数列
分析:按照上述阶乘的分析过程分析,这里不赘述
?
1
2
3
4
function
fibonacci (n) {
//此方法应使用尾递归法进行优化,这里不作优化,简单实现
if
( n <= 1 ) {
return
1};
return
fibonacci(n - 1) + fibonacci(n - 2);}
六、实现一个计算字符串字节长度的函数
分析:首先我们要知道英文的字节长度是1,而中文的字节长度是2,但是如何判断当前字符位是汉字还是英文呢,通过charCodeAt来判断当前字符位的unicode编码是否大于255,如何大于255则是汉字,那就给字符串的字节长度加2,如果小于255则是英文,就给字符串的字节长度加1,以下按照这个思路实现
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)返回的结果变成字符串形式,再去判断,实现如下
?
1
2
3
4
5
6
7
8
9
function
isNaN(num) {
var
ret = Number(num)
ret +=
''
if
(ret ===
'NaN'
) {
return
true
}
return
false
}
isNaN(
'123abc'
)
// true
八、实现数组的push函数
分析:首先push函数是位于Array构造函数的原型对象上的方法,所以要在Array.prototype上去定义,然后再分析push函数的作用是往数组的末尾添加元素,可以添加任意个数的元素,并且最终返回数组的长度,实现代码如下
?
1
2
3
4
5
6
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方法去做才唯一能够最准确判断当前值为什么数据类型,实现代码如下
?
1
2
3
window.
typeof
=
function
(value) {
return
Object.prototype.toString.call(val).slice(8, -1)
}
八、实现数组的去重方法
分析:首先因为是给所有数组实例实现一个去重方法,所以同样是在原型链上进行编程
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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]
?
1
2
3
4
5
6
7
8
9
10
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
}
?
1
2
3
4
5
Array.prototype.unique =
function
() {
//利用ES6的Set
var
result =
new
Set(
this
)
//生成一个类数组
return
Array.from(result)
//通过Array.from将类数组转换成真正的数组
}
?
1
2
3
4
5
6
Array.prototype.unique =
function
() {
//利用Array.prototype.filter返回符合条件的元素
//利用Array.prototype.indexOf返回数组中第一次出现当前元素的索引值
//该方法写法最为优雅,一行代码搞定,函数式编程
return
this
.filter((item, index) =>
this
.indexOf(item) === index)
}
九、实现函数的防抖、节流
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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操作符
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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、原型链继承:子类型的原型对象为父类型的实例对象
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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调用父类的构造函数实现继承
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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调用父类构造函数,继承父类的属性并保留传参的优点,再通过将父类的实例作为子类的原型对象,实现继承
?
1
2
3
4
5
6
function
Person (name, age) {
this
.name = name
this
.age = age
}
Person
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。
您可能感兴趣的文章:
原文 https://www.jb51.net/article/159785.htm