Javascript函数

来源:互联网 发布:季后赛数据排名 编辑:程序博客网 时间:2024/06/05 20:13

掌握内容:

◆ 如何定义和使用函数;

◆ 如何向函数传递参数;

◆ 了解我们可以“免费”调用哪些预定义函数;

◆ 了解 JavaScript 中的变量作用域;

◆ 理解“函数也是数据”的概念,并将函数视为一种特殊的数据类型。

函数应用:

◆ 匿名函数的调用;

◆ 即时(自调)函数;

◆ 内嵌函数(在函数内部定义的函数);

◆ 以函数为返回值的函数;

◆ 能重定义自身的函数;

◆ 闭包。


什么是函数

所谓函数,本质上是一种代码的分组形式。我们可以通过这种形式赋予某组代码一个名字,以便于之后的调用。

一般来说,函数声明通常由以下几部分组成。

function sum(a, b) {  var c = a + b;  return c;}

◆ 关键词 function。

◆ 函数名称 sum

◆ 函数所需参数

◆ 函数所要执行的代码块,即函数体

◆ return 子句。 函数返回值, 如果没有显示的返回值,则默认它的返回值为 undefined。

调用函数 (call)

var result = sum(1,2);console.log(result) //->3

参数

参数可分为形参(形式参数)与实参(实际参数)两种,形参是指定义函数时所用的那些参数,而实参则指的是在调用函数时所传递的那些参数。

我们还可以创建一些在参数数量方面更为灵活的函数。这得益于函数内部的 arguments 变量,该变量为内建变量,每个函数中都能调用。它能返回函数所接收的所有参数。

function args() {  return arguments;}args() //->[]args( 1, 2, 3, 4, true, 'ninja'); //->[1, 2, 3, 4, true, "ninja"]

完善 sum 函数:

function sum() {  var res = 0;  for(var i = 0; i < arguments.length; i++) {    res += arguments[i];  }  return res;}sum(1, 2, 3) //->6sum() //->0sum(5) //->5

预定义函数

JavaScript 引擎中有一组可供随时调用的内建函数。

◆ parseInt() 将其收到的任何输入值(通常是字符串)转换成 整数类型 输出。如果转换失败就返回 NaN。

◆ parseFloat() 与 parseInt()基本相同,只不过它仅支持将输入值转换为十进制数。

◆ isNaN() 通过 isNaN(),我们可以确定某个输入值是否是一个可以参与算术运算的数字。因而,该函数也可以用来检测 parseInt()和 parseFloat()的调用成功与否。

◆ isFinite() 用于检查其参数是否是无穷大。

◆ encodeURI() 把字符串作为 URI 进行编码。

◆ decodeURI() 可对 encodeURI() 函数编码过的 URI 进行解码。

◆ encodeURIComponent() 可把字符串作为 URI 组件进行编码。

◆ decodeURIComponent() 可对 encodeURIComponent() 函数编码的 URI 进行解码。

◆ eval()

请注意 encodeURIComponent() 函数 与 encodeURI() 函数的区别之处,前者假定它的参数是 URI 的一部分(比如协议、主机名、路径或查询字符串)。因此 encodeURIComponent() 函数将转义用于分隔 URI 各个部分的标点符号。

encodeURIComponent("http://www.baidu.com?a=你好") //->"http%3A%2F%2Fwww.baidu.com%3Fa%3D%E4%BD%A0%E5%A5%BD"encodeURI("http://www.baidu.com?a=你好") //->"http://www.baidu.com?a=%E4%BD%A0%E5%A5%BD"

变量的作用域

在 JavaScript 中,变量的定义并不是以代码块({})作为作用域的,而是以函数作为作用域。

在 JavaScript 中,术语“全局变量”指的是定义在所有函数之外的变量(也就是定义在全局代码中的变量),与之相对的是“局部变量”,所指的则是在某个函数中定义的变量。函数内的代码可以像访问自己的局部变量那样访问全局变量,反之则不行。

如果我们声明一个变量时没有使用 var 语句,该变量就会被默认为全局变量。

◆ 尽量将全局变量的数量降到最低,以避免命名冲突。
◆ 最好总是使用 var 语句来声明变量。
◆ 可以考虑使用“单一 var”模式,即,仅在函数体内的第一行使用一个 var 来定义这个作用域中所有需要的变量。

变量提升

当 JavaScript 执行过程进入新的函数时,这个函数内被声明的所有变量都会被移动(或者说提升)到函数最开始的地方。

var a = 123;function f() {   alert(a); // undefined  var a = 1;  alert(a); // 1}

f 函数等同于

function f() {   var a;  alert(a); // undefined  a = 1;  alert(a); // 1}

函数也是数据

函数表达式(2种)也叫函数字面量:

不希望函数声明提前的,特别是在一些初始换函数情况下,可以考虑用函数表达式。

var f = function() {} //没有函数表示标识符,匿名函数

var f = function fun() {} //有函数表示符fun ,即命名函数表达式

  1. 可以用f()调用该命名函数表达式,fun只是一个标识符,不能调用函数。
  2. 标识符fun只有在函数作用域中有效,在外面的作用域中无效。 (递归函数)

1. 匿名函数

没有名字的函数->匿名函数

◆ 您可以将匿名函数作为参数传递给其他函数,这样,接收方函数就能利用我们所传递的函数来完成某些事情。
◆ 您可以定义某个匿名函数来执行某些一次性任务。

2. 回调函数
当我们将函数 A 传递给函数 B,并由 B 来执行 A 时, A 就成了一个回调函数( callback functions )。如果这时 A 还是一个无名函数,我们就称它为匿名回调函数。

function invokeAdd(a, b){  return a() + b();}function one() {  return 1;}function two() {  return 2;}invokeAdd(one, two); //->3//匿名回调函数invokeAdd(function () {  return 1;}, function () {  return 2;})

回调函数优势:
◆ 它可以让我们在不做命名的情况下传递函数(这意味着可以节省变量名的使用)。
◆ 我们可以将一个函数调用操作委托给另一个函数(这意味着可以节省一些代码编写工作)。
◆ 它们也有助于提升性能

function multiplyByTwo(a, b, c, callback) {  var i,  ar = [  ];  for (i = 0; i < 3; i++) {    ar[i] = callback(arguments[i] * 2);  }  return ar;}function addOne(a) {  return a + 1;}multiplyByTwo(1, 2, 3, addOne); //->[3, 5, 7]multiplyByTwo(1, 2, 3, function (a) {  return a + 2;}); //->[4, 6, 8]

3. 自执行函数(即时函数

使用即时(自调)匿名函数的好处是不会产生任何全局变量。当然,缺点在于这样的函数是无法重复执行的(除非您将它放在某个循环或其他函数中)。这也使得即时函数非常适合于执行一些一次性的或初始化的任务

(function (name) {  alert('Hello ' + name + '!');}) ('zula');

4. 内部(私有)函数

内部函数优势:
◆ 有助于我们确保全局名字空间的纯净性(这意味着命名冲突的机会很小)。
◆ 确保私有性—这使我们可以选择只将一些必要的函数暴露给“外部世界”,而保留属于自己的函数,使它们不为该应用程序的其他部分所用。

function outer(param) {  function inner(theinput) {    return theinput * 2;  }  return 'The result is ' + inner(param);}outer(2) //->4

inner函数在外部是看不到的。。

5. 返回函数的函数

function a() {  alert('A');  return function () {    alert('B');  }}var newFunc = a(); //->alert('A')newFunc(); //->alert('B')

6. 重写自己的函数

看书没大懂有啥用。。。。案例是:

var a = (function () {  function someSetup() {   setup = 'done';  }  function actualWork() {    alert('Worky-worky');  }  someSetup();  return actualWork;}())setup // donea // actualWork

闭包

  • 闭包#1
var a = 'global variable';var F = function () {  var b = 'local variable';  var N = function () {    var c = 'inner local';    return b;  };  return N;};b //-> ReferenceError: b is not definedvar inner = F();inner(); //->local variable

函数 F 中包含了局部变量 b,因此后者在全局空间里是不可见的

函数 N 有自己的私有空间,同时也可以访问 f()的空间和全局空间,所以 b 对它来说是可见的。

因为 F() 是可以在全局空间中被调用的(它是一个全局函数),所以我们可以将它的返回值赋值给另一个全局变量,从而生成一个可以访问 F() 私有空间的新全局函数

  • 闭包#2

….不喜欢这种写法。。。。

var inner; // placeholdervar F = function () {  var b = 'local variable';  var N = function () {    return b;  };  inner = N;};F()inner() //->local variable
  • 相关定义与闭包

如果一个函数会在其父级函数返回之后留住对父级作用域的链接的话,相关闭包就会被创建起来。但其实每个函数本身就是一个闭包,因为每个函数至少都有访问全局作用域的权限,而全局作用域是不会被破坏的。

function F(param) {  var N = function(){   return param;  };  param++;  return N;}var inner = F(123);inner() //->124

var inner = F(123); F 执行后返回子级函数,param 在 N 里还有被用到,所以没有销毁,执行 inner 时,返回 param

  • 循环中的闭包

  • 迭代器

function setup(x) {  var i = 0;  return function () {    return x[i++];  }}var next = setup(['a',[1,2,3],'c'])next()