这个问题挺好的,连着这个问题可以把 this 和 lambda 都给讲了。

——————————————————————————————

函数

首先,稍了解 js 都该知道,js 的 Function 有很多特性,比如说闭包(捕获外部变量),比如说可以作为值传递(函数亦为对象),还有就是 this(动态作用域) 。

当我们放弃了这些特性,剩下来的那个简陋的东西那就是“函数”。

// 声明function add_1(a){
return a + 1
}
// 调用let num_4 = add_1(3)

说白了就是一段可复用的代码块,有个入参可以传递数据,有个返回值可以得到结果罢了。

方法

当学了面向对象编程后,你会发现这么简陋的一个函数是无法满足 OOP 的需求。

OOP 要求将对对象的操作绑定到对象上。我们首先可以想到,大不了再对象上面放一个指向这个函数的指针不就行了。

然而并不行,在对象的上放个函数指针没什么,但问题是你没法通过这个方法访问到当前所操作的对象。于是很自然地就会想到,干脆在函数里面放一个固定地变量指向调用者吧。

// 通过字面量地方式创造一个对象let someone = {
name:'张三',
wife: '李四',
setNewWife(name){
this.wife = name
}
}
// 调用对象上地方法someone.setNewWife('王五')

构造函数

显然通过字面量地方式创造一个对象实在麻烦。一般地语言是通过 class 来构建对象,class 内部有着一个构造函数可以对对象进行初始化。

既然我们现在已经有通过固定地变量 this 来访问对象这个设定,那么就通过关键字 new 在函数内部新建一个空对象,以实现构造函数。

// 声明一个构造函数// 当用关键字 new 调用的时候// 函数内部指向一个新建的以构造函数的prototype属性为原型的空对象// 执行完成后会返回这个新的对象function Someone(name){
this.name = name
this.wife = null
}
Someone.prototype.setNewWife = function(name){
this.wife = name
}
let some = new Someone('张三')

再加上原型继承,OOP 的基础算是齐活了。

Lambda

随着进一步的学习,你发现除了面向对象这一个范式,世界上竟然还有另一个范式 —— 函数式编程。

函数式编程其实就是围绕高阶函数展开的。高阶函数需要一个函数能作为值进行传递。其实很简单嘛,大不了传函数指针嘛?

然而并不行,仅仅传递函数指针并没有什么,但是一旦涉及到函数传递就会有关于作用域的问题。

之前的函数无法传递,那么调用也只能在声明的作用域内部进行调用,需要外部的值直接可以传进去。可是当你将函数作为返回值传递后,调用在声明的作用域外,当你声明这个函数的时候,完全没办法把参数传进去。

于是,就有了闭包(捕获外部变量)

function a() {
let num = 1
let newfunc = function (a, b) {
return a + b
}
// 在所声明的作用域内调用的时候,需要外部的值直接传 newfunc(num,1)
}
function b(){
let num = 1
return function(b){
// 作为返回值进行传递的时候,需要能捕获到外部作用域 num 的值 return num + b
}
}

——————————————————————————————

java 是相对纯粹的面向对象语言,所以方法见的比较多。JavaScript 将函数/方法/Lambda 的功能都揉合在一起,所以比较难区分。假如题主学过一些比较现代的多范式静态语言,应该就不会有这个疑问了,比如 rust 就将这三者区分的很明显。

这也是 Javascript 的著名失败设计之一。看起来把这些东西整合在一起很厉害,但用起来简直要命。

当我们声明一个函数的时候,我们对其功能是有比较清晰的认识的。然而对于调用方而言,一个函数拿到手了,到底是普通的函数,还是 lambda(引用了外部变量),还是方法(依赖于一个具体的对象),却是隐式的。

// 会报错,因为 document.getElementById 是依赖 document 的方法(function(getElementById){
getElementById('main')
})(document.getElementById)

其次就是因为每个函数内部隐式声明了 this ,所以函数闭包无法捕获 this(其实还有 arguments)这个外部变量,使得 JSer 经常需要写 var _this = this 。这一点在箭头函数中有所弥补。