目录
3.2.调用 myFunction() 与调用 window.myFunction() 相同。
4.函数Call使用 call() 方法,您可以编写能够在不同对象上使用的方法。
5.2.在数组上模拟max方法,可以使用 Math.max() 方法找到(数字列表中的)最大数字:
七、函数
1.函数定义
JavaScript 函数是通过 function 关键词定义的。
函数也可以通过名为 Function() 的内建 JavaScript 函数构造器来定义。
var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);
您实际上无需使用函数构造器。上面的例子这么写也是一样的:
var myFunction = function (a, b) {return a * b};
var x = myFunction(4, 3);
1.1.JavaScript 函数也可以使用表达式来定义。
函数表达式可以在变量中存储:
var x = function (a, b) {return a * b};
<!DOCTYPE html>
<html>
<body>
<p id="demo"></p>
<script>
var x = function (a, b) {return a * b};
document.getElementById("demo").innerHTML = x(4, 3);
</script>
</body>
</html>
JavaScript 函数可用在表达式中:
function myFunction(a, b) {return a * b;}
var x = myFunction(4, 3) * 2;
1.2.自调用函数
如果表达式后面紧跟 () ,则会自动调用。
不能自调用声明的函数。
通过添加括号,来说明它是一个函数表达式:
<p id="demo"></p>
<script>
(function () {
document.getElementById("demo").innerHTML = "Hello! I called myself";
})();
</script>
1.3.函数是对象
- arguments.length 会返回函数被调用时收到的参数数目:
<p id="demo"></p>
<script>
function myFunction(a, b) {
return arguments.length; //返回实际传入的参数个数
}
document.getElementById("demo").innerHTML = myFunction(4, 3);
</script>
执行结果:2
- toString() 方法以字符串返回函数:
<p id="demo"></p>
<script>
function myFunction(a, b) {
return a * b;
}
document.getElementById("demo").innerHTML = myFunction.toString();
</script>
执行结果:function myFunction(a, b) { return a * b; }
1.4.箭头函数(用简短的语法来编写函数表达式。)
您不需要 function 关键字、return 关键字和花括号。
<p id="demo"></p>
<script>
const x = (x, y) => x * y;
document.getElementById("demo").innerHTML = x(5, 5);
</script>
返回结果:25
- 如果函数是单个语句,则只能省略 return 关键字和大括号。因此,保留它们可能是一个好习惯:
箭头函数没有自己的 this。它们不适合定义对象方法。
箭头函数未被提升。它们必须在使用前进行定义。
使用 const 比使用 var 更安全,因为函数表达式始终是常量值。
<p id="demo"></p>
<script>
const x = (x, y) => { return x * y };
document.getElementById("demo").innerHTML = x(5, 5);
</script>
2.JavaScript 函数参数
JavaScript 函数不会对参数值进行任何检查。
2.1.参数规则
JavaScript 函数定义不会为参数(parameter)规定数据类型。
JavaScript 函数不会对所传递的参数(argument)实行类型检查。
JavaScript 函数不会检查所接收参数(argument)的数量。
2.2.参数默认
如果调用参数时省略了参数(少于被声明的数量),则丢失的值被设置为:undefined。
有时这是可以接受的,但是有时最好给参数指定默认值:
<p id="demo"></p>
<script>
function myFunction(x, y) {
if (y === undefined) {
y = 0;
}
return x * y;
}
document.getElementById("demo").innerHTML = myFunction(4);
</script>
返回结果:0
2.3.arguments 对象
如果函数调用的参数太多(超过声明),则可以使用 arguments 对象来达到这些参数。
arguments 对象包含函数调用时使用的参数数组。
- 这样,您就可以简单地使用函数来查找(例如)数字列表中的最高值:
<p id="demo">找到最大的数字</p>
<script>
function findMax() {
var i;
var max = -Infinity;
for(i = 0; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
document.getElementById("demo").innerHTML = findMax(4, 5, 6);
</script>
返回结果:6
- 创建一个函数来总和所有输入值:
<p id="demo">所有参数的总和</p>
<script>
function sumAll() {
var i;
var sum = 0;
for(i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
document.getElementById("demo").innerHTML = sumAll(1, 123, 500, 115, 44, 88);
</script>
返回结果:871
3.函数调用
3.1.以函数形式调用函数
<p id="demo"></p>
<script>
function myFunction(a, b) {
return a * b;
}
document.getElementById("demo").innerHTML = myFunction(10, 2);
</script>
返回结果:20
3.2.调用 myFunction() 与调用 window.myFunction() 相同。
全局函数自动成为 window 方法。
<p id="demo"></p>
<script>
function myFunction(a, b) {
return a * b;
}
document.getElementById("demo").innerHTML = window.myFunction(10, 2);
</script>
3.3.this关键词
在 JavaScript 中,被称为 this 的事物,指的是“拥有”当前代码的对象。
this 的值,在函数中使用时,是“拥有”该函数的对象。
请注意 this 并不是变量。它属于关键词。您无法改变 this 的值。
3.4.全局对象
当不带拥有者对象调用对象时,this 的值成为全局对象。在 web 浏览器中,全局对象就是浏览器对象。
本例以 this 的值返回这个 window 对象:
<p id="demo"></p>
<script>
var x = myFunction();
function myFunction() {
return this;
}
document.getElementById("demo").innerHTML = x;
</script>
返回结果:[object Window]
3.5.作为方法来调用函数
在 JavaScript 中,您可以把函数定义为对象方法。
下面的例子创建了一个对象(myObject),带有两个属性(firstName 和 lastName),以及一个方法(fullName):
<p id="demo"></p>
<script>
var myObject = {
firstName:"Bill",
lastName: "Gates",
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
document.getElementById("demo").innerHTML = myObject.fullName(); // 将返回 "Bill Gates"
</script>
返回结果:Bill Gates
3.6.通过函数构造器来调用函数
构造器调用会创建新对象。新对象会从其构造器继承属性和方法。
构造器内的 this 关键词没有值。
this 的值会成为调用函数时创建的新对象
如果函数调用的前面是 new 关键字,那么这是一个构造函数调用。
<p id="demo"></p>
<script>
// 这是函数构造器:
function myFunction(arg1, arg2) {
this.firstName = arg1;
this.lastName = arg2;
}
var x = new myFunction("Bill","Gates") // 创建了一个新对象:
document.getElementById("demo").innerHTML = x.firstName; // 会返回 "Bill"
</script>
返回结果:Bill
4.函数Call使用 call() 方法,您可以编写能够在不同对象上使用的方法。
4.1.函数是对象方法
在 JavaScript 中,函数是对象的方法。
如果一个函数不是 JavaScript 对象的方法,那么它就是全局对象的函数(参见前一章)。
下面的例子创建了带有三个属性的对象(firstName、lastName、fullName)。
fullName 属性是一个方法。person 对象是该方法的拥有者。
fullName 属性属于 person 对象的方法。
<p id="demo"></p>
<script>
var myObject = {
firstName:"Bill",
lastName: "Gates",
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
x = myObject.fullName();
document.getElementById("demo").innerHTML = x; // 将返回 "Bill Gates"
</script>
返回结果:Bill Gates
4.2.JavaScript call()方法
call() 方法是预定义的 JavaScript 方法。
它可以用来调用所有者对象作为参数的方法。
通过 call(),您能够使用属于另一个对象的方法。
本例调用 person 的 fullName 方法,并用于 person1:
<p id="demo"></p>
<script>
var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var person2 = {
firstName:"Steve",
lastName: "Jobs"
}
var x = person.fullName.call(person1); // 将返回 "Bill Gates"
document.getElementById("demo").innerHTML = x;
</script>
返回结果:Bill Gates
4.3.带参数的 call() 方法
call() 方法可接受参数:
<p id="demo"></p>
<script>
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var person2 = {
firstName:"Steve",
lastName: "Jobs"
}
var x = person.fullName.call(person1, "Seatle", "USA");
document.getElementById("demo").innerHTML = x;
</script>
返回结果:Bill Gates,Seatle,USA
5.JavaScript 函数 Apply
通过 apply() 方法,您能够编写用于不同对象的方法。
apply() 方法与 call() 方法非常相似:
在本例中,person 的 fullName 方法被应用到 person1:
<p id="demo"></p>
<script>
var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var x = person.fullName.apply(person1); // 将返回 "Bill Gates"
document.getElementById("demo").innerHTML = x;
</script>
返回结果:Bill Gates
5.1.call() 和 apply() 之间的区别
call() 方法分别接受参数。
apply() 方法接受数组形式的参数。
如果要使用数组而不是参数列表,则 apply() 方法非常方便。
- 带参数的 apply() 方法
apply() 方法接受数组中的参数:
<p id="demo"></p>
<script>
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var x = person.fullName.apply(person1, ["Seatle", "USA"]); //apply() 方法接受数组形式的参数。
document.getElementById("demo").innerHTML = x;
</script>
- 与 call() 方法对比:
<p id="demo"></p>
<script>
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var person2 = {
firstName:"Steve",
lastName: "Jobs"
}
var x = person.fullName.call(person1, "Seatle", "USA"); //call() 方法分别接受参数。
document.getElementById("demo").innerHTML = x;
</script>
5.2.在数组上模拟max方法,可以使用 Math.max() 方法找到(数字列表中的)最大数字:
在 JavaScript 严格模式下,如果 apply() 方法的第一个参数不是对象,则它将成为被调用函数的所有者(对象)。在“非严格”模式下,它成为全局对象。
<p id="demo"></p>
<script>
document.getElementById("demo").innerHTML = Math.max(1,2,3);
</script>
返回结果:3.
这些例子会给出相同的结果:
document.getElementById("demo").innerHTML = Math.max.apply(null, [1,2,3]);
document.getElementById("demo").innerHTML = Math.max.apply(Math, [1,2,3]); // 也会返回 3
document.getElementById("demo").innerHTML = Math.max.apply(" ", [1,2,3]); // 也会返回 3
document.getElementById("demo").innerHTML = Math.max.apply(0, [1,2,3]); // 也会返回 3
6.JavaScript 闭包
JavaScript 变量属于本地或全局作用域。全局变量能够通过闭包实现局部(私有)
全局变量活得和您的应用程序(窗口、网页)一样久。
局部变量活得不长。它们在函数调用时创建,在函数完成后被删除。
6.1.一个计数器的困境
假设您想使用变量来计数,并且您希望此计数器可用于所有函数。
您可以使用全局变量和函数来递增计数器:
<p id="demo"></p>
<script>
// 初始化计数器
var counter = 0;
// 递增计数器的函数
function add() {
counter += 1;
}
// 调用三次 add()
add();
add();
add();
// 计数器目前应该是 3
document.getElementById("demo").innerHTML = "计数器是:" + counter;
</script>
运行结果:计数器是:3
6.2.JavaScript 嵌套函数
JavaScript 支持嵌套函数。嵌套函数可以访问其上的作用域。
在本例中,内部函数 plus() 可以访问父函数中的 counter 计数器变量:
<p id="demo">0</p>
<script>
document.getElementById("demo").innerHTML = add();
function add() { //父函数add()
var counter = 0;
function plus() { //子函数plus()
counter += 1; //访问父函数中的counter变量
}
plus();
plus();
plus();
return counter; //返回计数器的值
}
</script>
返回结果:3
这样即可解决计数器困境,如果我们能够从外面访问 plus() 函数。
我们还需要找到只执行一次 counter = 0 的方法。
我们需要闭包(closure)。
6.3.JavaScript闭包
<p>使用局部变量计数。</p>
<button type="button" onclick="myFunction()">计数!</button>
<p id="demo">0</p>
<script>
//变量 add 的赋值是自调用函数的返回值。
var add = (function () { //这个自调用函数只运行一次。
var counter = 0; //它设置计数器为零
return function () { //并返回函数表达式。
counter += 1;
return counter;
}
})();
function myFunction(){
document.getElementById("demo").innerHTML = add();
}
</script>
这样 add 成为了函数。最“精彩的”部分是它能够访问父作用域中的计数器。
这被称为 JavaScript 闭包。它使函数拥有“私有”变量成为可能。
计数器被这个匿名函数的作用域保护,并且只能使用 add 函数来修改。
闭包指的是有权访问父作用域的函数,即使在父函数关闭之后。