JavaScript终极BOSS,函数
你确定掌握了JS的函数,真的确定吗?
警告:最后一站:秋名山,座下乃AE86,无法保证不撒豆腐,路途颠簸刺激,请务必拉好扶手!
JavaScript函数函数过于恶心,我们由浅入深,一点一点来,相信全篇下来,不懂也能做到心里有数了。
经典函数的定义
函数定义有三种情况,具名函数、函数表达式与匿名函数。
函数的作用,简单理解:专门解决某个问题或业务的功能模块。
-
具名函数
-
函数表达式
- 匿名函数
具名函数
具名函数,就是最常见的普通函数及其声明。
function func1(参数) {
内容
return x // return 可选
}
关键词 | 说明 |
---|---|
function | 函数声明前缀,就像变量的var, let, const一样。 |
func1 | func1就是函数名,当然可以随便什么名字。 |
参数 | 可选的,所谓参数就是给这个函数运行的时候提供的资源,并且是可以直接在函数内部调用的变量。 |
内容 | 常规的js代码,可以使用参数。 |
return | 函数的返回值,就是这个函数执行完之后给外部执行者一个结果,当然也可以不给。 |
参数注意一下,参数可以没有,可以一个,也可以多个。多个参数使用
,
隔开。这里不讲解arguments,需要了解的请点击:js arguments
比如你要做个平方处理,弄个函数如下:
function getSquare(num) {
return num * num // 当然可以使用Math方法,这里不提。
}
let result = getSquare(987)
console.log(result) // 974169
又或者如下:
let initialNum = 987
function makeSquare() {
initialNum *= initialNum
}
makeSquare()
console.log(initialNum) // 974169
这两个函数使用相信大家没什么问题,主要说明一下里面的return区别。
第一个提供的是公共函数,就是你给我一个数,我帮你给平方并且把结果返回给你,所以需要return。
第二种是对已经有的数据处理,并不产生新的需要用到的变量,所以就不需要返回,也就不需要return。
不写return还是会默认返回一个值,其实JS操作都会返回一个值,即return一个值出来,如果是没有明确return什么东西,则返回的是undefined。
上述例子改写一下,如下:
let result = getSquare(987)
function getSquare(num) {
return num * num // 当然可以使用Math方法,这里不提。
}
console.log(result) // 974169
这种情况下没有报错,按说getSquare在使用后声明,应该会报错才是,但实际上不是,这里就有一个小知识点:函数的声明提升。实际代码解释后如下:
// 注意实际上被解释器提升到这里了。
let getSquare
getSquare = function(num) {
return num * num // 当然可以使用Math方法,这里不提。
}
let result
result = getSquare(987)
console.log(result) // 974169
上面看不懂的请回去看我之前的文章:JavaScript变量。
这里要记住一点:具名函数是JS所有类型中的一等公民,所有提升函数都会到当前作用域的最上面!
this内容在后面的ES6箭头函数那里
匿名函数
function(参数(可选)) {
内容
return x // return 可选
}
匿名函数由于没有名字,定义后续无法使用,因为无名所以找不到。正因此,匿名函数多用来作为回调。如下:
// 函数func1有一个参数any,any由于会执行,所以是个函数,因为这里给这个函数名字了,所以传进来时候不需要名字,即匿名。
function func1(any) {
console.log('func1调用了')
any()
}
// 执行func1并传了一个匿名函数进去
func1(function() {
console.log('匿名函数调用了')
})
// func1调用了
// 匿名函数调用了
函数表达式
let func1 = function(参数(可选)) {
内容
return x // return 可选
}
与具名函数几乎一样,唯一区别就是无法做到完全的函数声明提升,此时不是具名函数也就不是一等公民了,如下:
let result = getSquare(987)
let getSquare = function(num) {
return num * num // 当然可以使用Math方法,这里不提。
}
console.log(result) // Uncaught ReferenceError: getSquare is not defined,未定义。
解释器是这么玩的:
let result
result = getSquare(987)
let getSquare
getSquare = function(num) {
return num * num // 当然可以使用Math方法,这里不提。
}
console.log(result)
看明白为什么报没有定义的错误了吧。
ES6的箭头函数
let func1 = (参数) => {
内容
return x // 可选
}
注意,只能使用类似函数表达式形式,不存在具名函数一说,匿名倒是常见。所以也没有提升了。
格式上与函数表达式差不太多,主要就是function换成了=>然后放到后面去了,光看格式还是很简单的。
箭头函数的意义:
-
写法与return
- this绑定处理
写法与return
不单单只是说把function去掉换成=>了,最主要是多了另一个强迫症福音,如下:
let af = num => num * num
let result = af(4)
console.log(result) // 16
首先,有没有看着很爽?大括号省了,这里注意,单句,还是单句才能省。单句说明在:JavaScript判断语句
再者,有没有发现没有return还是实现了return的功能?result打印居然不是undefined?这就是箭头函数的一个return功能点:单句的情况下,并且没有大括号包裹,默认返回此单句
let af = num => {
let a = 1
let b = 2
a + b
num * num
}
let result = af(4)
console.log(result) // undefined,如你所愿。
af = num => {
num * num
}
result = af(4)
console.log(result) // undefined,未能如你所愿。。。
个人倒是很喜欢这个不要括号的风格,与本尊爱的CoffeeScript又进了一步。
this
this对于函数来说,就是调用者。比如:a.func1()
那么原来func1里面的this都是a。如果是func1()
这种调用,则是当前作用域this,比如全局下调用,当前this是window,所以func1里面的this也是window。因为相当于window.func1()
。
具体this的相关如call,apply,bind以及new模式的this绑定。
但是箭头函数对此有特殊情况,具体区别见如下代码:
let obj1 = {
func1: function() {
console.log(this)
let obj2 = {
func2: function() {
console.log(this)
},
af2: () => console.log(this)
}
obj2.func2()
obj2.af2()
},
af1: () => console.log(this)
}
obj1.func1()
// obj1,谁调用this指向谁。
// obj2,谁调用this指向谁。
// obj1,自身不绑定this,this指向最近的被绑定this,若无,则Window。
obj1.af1() // Window,自身不绑定this,this指向最近的被绑定this,若无,则Window。
注意上述的代码与注释,说明了箭头函数与function函数this区别。
强制this绑定
与箭头函数无关
-
call
-
apply
- bind
call与apply
两者功能一致,都是强制绑定一个对象给函数调用,使得函数的this指向该对象,区别见表:
名称 | 区别 |
---|---|
call | x.call(obj, 参数1, 参数2, ...) |
apply | x.apply(obj, [参数1, 参数2, ...]) |
let obj = {
func: function(num) {
console.log(this)
console.log(num)
}
}
obj.func(1) // obj, 1
let objX = {
x: 'x'
}
obj.func.call(objX, 2) // objX, 2
obj.func.apply(objX, [2]) // objX, 2
就是call可以正常传参,而apply把参数组成数组传进去,个人比较喜欢call。
bind
call与apply使用后会直接运行,而bind使用后会复制一个已绑定的对象函数,然后需要手动运行,传参与call一致。
let obj = {
func: function(num) {
console.log(this)
console.log(num)
}
}
obj.func(1) // obj, 1
let objX = {
x: 'x'
}
let newFunc = obj.func.bind(objX, 2)
newFunc()
可以获取一个随时使用的被绑定指定对象的函数,优先考虑使用。
new
没什么太多可说的,秉承着谁调用this指向谁就对了。
function Obj() {
this.a = 1
this.func = function() {
console.log(this.a)
}
}
let obj = new Obj()
obj.a // 1
obj.func() // 1
new的this指向优先级高于其他,心里有个数就好。
闭包
获取与使用原本应该拿不到的局部作用域内的引用或变量。
一例胜千言:
// 常规
function add() {
let num = 1
num++
return num
}
add() // 2,调用的时候会新生成一个num,然后用完销毁num。
add() // 2,一样
add() // 2,一样
// 闭包
function add() {
let num = 1
return function() {
num++
return num
}
}
let result = add()
console.log(result)
// f() {
// num++
// return num
// }
result() // 2,num
result() // 3,num
获取并操作本该获取不到的num(当前是全局作用域,而num是在add函数作用域)。
恩,关于函数的知识点就说到这里了,喜欢我的文章请记得关注一波啊,我会定期更新技术文章。
共同学习,写下你的评论
评论加载中...
作者其他优质文章