JavaScript练习笔记(6)

目录

七、函数

1.函数定义

1.1.JavaScript 函数也可以使用表达式来定义。

1.2.自调用函数

1.3.函数是对象

1.4.箭头函数(用简短的语法来编写函数表达式。)

2.JavaScript 函数参数

2.1.参数规则

2.2.参数默认

2.3.arguments 对象

3.函数调用

3.1.以函数形式调用函数

3.2.调用 myFunction() 与调用 window.myFunction() 相同。

3.3.this关键词

3.4.全局对象

3.5.作为方法来调用函数

3.6.通过函数构造器来调用函数

4.函数Call使用 call() 方法,您可以编写能够在不同对象上使用的方法。

4.1.函数是对象方法

4.2.JavaScript call()方法

4.3.带参数的 call() 方法

5.JavaScript 函数 Apply

5.1.call() 和 apply() 之间的区别

5.2.在数组上模拟max方法,可以使用 Math.max() 方法找到(数字列表中的)最大数字:

6.JavaScript 闭包

6.1.一个计数器的困境

6.2.JavaScript 嵌套函数

6.3.JavaScript闭包

 


七、函数

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 函数来修改。

闭包指的是有权访问父作用域的函数,即使在父函数关闭之后。

 

猜你喜欢

转载自blog.csdn.net/qq_35831134/article/details/110730712