`
毒药001
  • 浏览: 5350 次
  • 性别: Icon_minigender_1
  • 来自: 昆明
最近访客 更多访客>>
社区版块
存档分类
最新评论

学习面向对象javascript(二)函数

阅读更多

在这篇文章中,将会介绍一些function的知识,比如function的使用,变量作用域,匿名函数,回调,自执行函数,内部函数,闭包等相关的知识。其中,闭包的知识会在下一次的文章中介绍。

function的使用

javascript是非常灵活的语言。
比如,定义一个函数

 

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

 

执行sum(1,2)得到3,
执行sum(1),由于javascript允许少传参数,所以后面一个参数将被设成undefined,所以得到NaN,
执行sum(1,2,3,4,5,6),javascript也允许多传参数,后面多余的参数将会被忽略,所以得到3。
可见javascript是非常灵活的。
另外,当创建一个function的时候,javascript会自动创建一个叫做arguments的数组,里面包含了所以参数。

 

function args() {
     return arguments;
}

 

args();  // []
args( 1, 2, 3, 4, true, 'ninja');  // [1, 2, 3, 4, true, "ninja"]
 

 

作用域

在javascript中,变量不是被定义在一个代码块里面的,而是在一个function里面。也就是说,如果在function内部定义一个临时变量,那么在function外面是没法访问到的,然而将变量定义在一个if或者for代码块里面,在代码块外面是可以访问得到的。如果在任何function外部定义变量,那么这个变量就是全局变量,全局变量在任何function里面都是可以访问得到的。下面我们来看一下例子:

 

var global = 1;
function f() {
  var local = 2;
  global++;
  return global;
}
f();  // 2
local;  // ReferenceError: local is not defined

 

我们看到,在函数f里面成功访问到了global变量。但是在函数外部,访问不到local变量。再看下面的代码:

 

function f() {
    if(true){
        var local = 0;
    }
    local++;
    return local;
}
f();  // 1

 

可以发现,local变量并不是出了if块就不能被访问了。在代码块外面同样可以访问。由此看来javascript的变量的作用域是函数级的,不是块级的。
另外,值得一提的是,如果在函数中定义变量时,没用用var来声明,那么这个变量会被定义为全局变量。看下面代码:

 
function f() { 
    local=2; 
}
local;  // ReferenceError: local is not defined
f();  // undefined
local;  // 2

 

可以发现,在f()函数被调用前,local变量是不存在的,调用后,local可以在函数外部被访问,成为全局变量。
因此,在我们平时开发中,应该尽量用var来定义变量。避免定义全局变量,可以想象多个人在一个脚本中对一个全局变量操作,是相当难控制的。
在一个函数中,定义了一个和外部全局变量同名的变量是,在函数内,局部变量的优先级高于全局变量。为了直观一点,看下面的代码:

 

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

 

这段代码并不像你所想的一样,第一个alert弹出123,第二个alert弹出1,而是分别弹出undefined和1。这正是因为在函数内部,局部变量的优先级高于全局变量,所以,局部变量会覆盖所有同名的全局变量。

函数也是数据

在javascript中,函数也是数据,定义函数可以有以下两种方式:

 

function f(){
    return 1;
}
var f = function(){
    return 1;
}

 

用typeof来验证f,返回"function",因此,函数是一种特殊的数据。同时,函数还可以像普通变量一样赋值给其他变量,甚至删除掉。

 

var sum = function(a, b) {
    return a + b;
}
var add = sum;
delete sum;  // true
typeof sum;  // "undefined"
typeof add;  // "function"
add(1,2);  // 3

匿名函数

在javascript中,function可以在不给予函数名的情况下使用。比如:

 

function(a){
    return a;
}


但是这样的函数并没有什么用处,要让他能被调用,可以有下面两种方法:

  • 把一个匿名函数当做函数B的参数,然后在函数B中做一些有用的操作。
  • 可以定义一个匿名函数并且立即执行他。

下面我们针对这两种方法来进行更细一些的了解。

 

回调函数

由于函数可以像其他数据一样被赋给变量,能被定义、删除、复制,所以,同样的也可以被当做参数传递到另一个函数。
下面的例子是向函数中传入两个函数,执行以后返回两个函数返回值的和。

 

function invoke_and_add(a, b){
  return a() + b();
}

 

然后定义两个简单的函数

 

function one() {
  return 1;
}
function two() {
  return 2;
}

 

现在我们把这两个函数传入到invoke_and_add方法中。

 

invoke_and_add(one, two);  // 3

 

执行以后,返回3。
另外,同样可以传入两个匿名函数来试试。

 

invoke_and_add(function(){return 1;}, function(){return 2;});  // 3

 

像这样类似的,传入一个函数A到另一个函数B中,在B中执行A,A就叫做回调函数。如果A是匿名函数的话,可以叫做匿名回调函数。
再看一个例子:

 

/**
*把a,b,c 3个数乘以2以后,返回积的数组
*/
function multiplyByTwo(a, b, c) {
  var i, ar = []; 
  for(i = 0; i < 3; i++) {
    ar[i] = arguments[i] * 2;
  } 
  return ar;
}
function addOne(a) {
  return a + 1;
}

 测试:

 

multiplyByTwo(1, 2, 3);  // [2, 4, 6]
addOne(100);  // 101

 

现在,我们需要传入3个数字,然后先对着3个数字乘以2,再在积上加1。我们通常会想到,先调用multiplyByTwo方法,在循环结果,把各个结果传入addOne方法,最后得到我们想要的。这样做,必然会需要循环数组两次来算出结果。
有了回调函数,我们就可以这样做,稍微把multiplyByTwo方法修改一下。

 

function multiplyByTwo(a, b, c, callback) {
  var i, ar = []; 
  for(i = 0; i < 3; i++) {
    ar[i] = callback(arguments[i] * 2);
  } 
  return ar;
}

 

多加入一个callback参数,在方法中一次性就得到最终需要的结果。

 

multiplyByTwo(1, 2, 3, addOne);  // [3, 5, 7]

 

由此,可见使用callback函数,不仅可以减少我们的代码量,还可以优化性能。

自执行函数

下面我们来看匿名函数的另一种用法—自执行函数。它可以在函数被定义以后马上被执行。

 

(
  function(){
    alert('boo');
  }
)()

 

 将匿名函数放在一对小括号里面,后面在跟一对小括号就可以。后面的小括号内可以传入函数所需要的实参。比如:

 

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

 

使用自执行函数的好处在于,你可以不必为函数创建全局变量。但是缺点是,自执行函数只能执行一次,除非你把它放在循环里或者其他方法里。因此,自执行函数适合用在一次性执行的地方或者初始化的地方。

 

内部函数(私有函数)

在函数中,还可以定义另一个函数。比如:

 

function a(param) {
  function b(theinput) {
    return theinput * 2;
  };
  return 'The result is ' + b(param);
};

 

这样的函数b就叫做内部函数。执行一下。

 

a(8);  // "The result is 16"
b(2);  // b is not defined

 

可以发现,函数b提示没有定义。因此也叫私有函数。
定义内部函数有什么好处呢?
首先,可以保持外部命名空间比较干净,减小了命名冲突的几率。
第二,由于它的私有性,你可以把不想提供给外部的函数私有化。

 

函数中返回函数

在之前,我们知道,函数总是返回一个值,如果函数没有显式的返回一个值,那么他将返回undefined。同样,函数也可以返回一个函数。

 

function a() {
  alert('A!'); 
  return function(){
    alert('B!'); 
  };
}

 

在上面这个例子中,函数a完成了自己的工作(弹出“A!”),之后又返回一个做别的工作(弹出“B!”)的函数。你可以把返回的这个函数重新赋值给一个变量。然后把这个变量像其他普通函数一样调用。

 

var newFunc = a();   // 弹出"A!"
newFunc();  //弹出"B!"

 

如果你不想重新定义一个变量就立即执行return的函数的话,你可以在外部函数后面加一对小括号来立即执行他。

 

a()();  // 先弹出"A!",再弹出"B!"

重写本函数

由于函数可以返回函数,因此你可以用新的函数来替换掉旧的函数。

 

a = a(); // 弹出"A!"
a = a(); // 弹出"B!"

 

你可以发现,第一次重写弹出A!,第二次重写弹出B!。
当一个函数有一些一次性的初始化工作要做时,这就很有用了。在函数被调用时,为了避开重复做一些不必要的事,可以在第一次调用完函数后重写他自己。
在上面的例子中,我们从外部把函数重写了。但是我们也可以在内部重写他。

 

function a() {
  alert('A!');
  a = function(){
    alert('B!');
  };
}

 

在第一次执行a()的时候,会弹出A!,我们可以把它看做是一次性初始化工作。
在这之后,每次执行a(),都会弹出B!

 

至此,函数方面的知识暂时介绍到这了。下一次的文章中会介绍函数的另一个重要特性----闭包的有关知识。

分享到:
评论

相关推荐

    面向对象JavaScript精要(英文原版pdf)

    《面向对象JavaScript精要》是一本非常有价值的书籍,不仅适合初学者入门,也适合有一定经验的开发者进阶学习。通过学习本书,读者可以全面掌握面向对象编程的基本概念,并学会如何将这些概念应用到JavaScript中,...

    面向对象javascript

    面向对象JavaScript教程 面向对象JavaScript是一种编程范式,它将JavaScript脚本编写转换为面向对象的思想。面向对象的JavaScript开发可以极大地提高开发效率和代码健壮性。 面向对象的JavaScript的特征包括: * ...

    面向对象JavaScript开发

    面向对象JavaScript开发是现代Web开发中不可或缺的一部分,它使得JavaScript能够构建复杂、可维护的应用程序。 面向对象编程是一种基于对象和类的编程范式,它强调数据和操作数据的方法的封装。在JavaScript中,...

    Javascript面向对象编程.

    JavaScript是一种广泛应用于Web开发的脚本语言,尤其在前端领域占据着核心地位。面向对象编程(Object-Oriented Programming,OOP)是...学习这些材料将有助于深入理解JavaScript的面向对象编程,提升你的编程技能。

    JavaScript学习深入—面向对象编程

    ### JavaScript学习深入—面向对象编程 #### 一、JavaScript中的类型概述 JavaScript作为一种动态的、弱类型的语言,其核心特点之一在于它灵活的对象模型。尽管JavaScript的基础架构支持面向对象编程(OOP),但在...

    JavaScript面向对象编程指南.pdf

    JavaScript作为一门浏览器语言的核心思想;面向对象编程的基础知识及其在... 《JavaScript面向对象编程指南》着重介绍JavaScript在面向对象方面的特性,展示如何构建强健的、可维护的、功能强大的应用程序及程序库

    JavaScript面向对象编程指南

    《JavaScript面向对象编程指南》内容包括:JavaScript作为一门浏览器语言的核心思想;面向对象编程的基础知识及其在JavaScript中的运用;数据类型、操作符以及流程控制语句;函数、闭包、对象和原型等概念,以代码...

    JAVASCRIPT 面向对象编程精要

    本文介绍了JavaScript面向对象编程的基本概念和技术细节,包括变量和对象的基础用法、函数的作用以及如何通过封装和继承来构建复杂的对象层次结构。JavaScript的独特之处在于它的灵活性和动态性,这使得它成为了一种...

    JavaScript面向对象编程指南(第2版).rar

    JavaScript是一种广泛...通过深入学习这本《JavaScript面向对象编程指南(第2版)》,开发者不仅能掌握JavaScript的面向对象编程基础,还能了解到实际项目中如何有效地运用这些知识,提升编程技巧和解决问题的能力。

    学习javascript面向对象 javascript实现继承的方式

    在JavaScript中,面向对象编程是通过构造函数、原型链和继承实现的。继承是面向对象编程的核心概念之一,它允许我们创建一个新对象,该对象继承现有对象的属性和方法。在JavaScript中,实现继承有多种方式,每种方式...

    javascript面向对象编程

    面向对象编程的基础知识及其在JavaScript中的运用;数据类型、操作符以及流程控制语句;函数、闭包、对象和原型等概念,以代码重用为目的的继承模式;BOM、DOM、浏览器事件、AJAX和JSON;如何实现JavaScript中缺失的...

    javascript面向对象编程(中文).pdf

    #### 二、面向对象的JavaScript基础 - **面向对象的概念**:面向对象编程(OOP)是一种编程范式,它使用“对象”来设计软件。在JavaScript中,对象是一组相关的属性和方法的集合。 - **JavaScript与OOP**:虽然...

    第15章 javascript面向对象与原型

    最后,面向对象的基础知识也是不可或缺的,由于JavaScript的面向对象实现方式比较特殊,所以学习者需要了解正统的面向对象编程基础。 创建对象是面向对象编程的基础。在JavaScript中创建对象有多种方式,最简单的一...

    Javascript面向对象编程

    ### JavaScript面向对象编程详解 #### 一、引言 JavaScript作为一种广泛使用的脚本语言,在Web开发领域占据着举足轻重的地位。尽管JavaScript本质上是一种基于原型的语言,但它也支持面向对象编程的一些特性,使得...

    js 面向对象实例

    面向对象编程在JavaScript中的实现主要基于以下三个概念:构造函数、原型和实例化。构造函数是一个特殊类型的函数,用于创建和初始化一个新对象。当你定义一个构造函数时,实际上是在定义一个对象类型。例如: ```...

    javascript实现根据函数名称字符串动态执行函数的方法示例

    此外,关于JavaScript的其它编程技巧,本篇介绍了多个专题,包括常用函数技巧、面向对象入门、json操作、切换特效、查找算法、错误与调试、数据结构与算法、遍历算法以及数学运算的用法总结。这些内容都是非常实用的...

    JavaScript 面向对象编程详细讲解文档

    JavaScript是一种动态类型的脚本语言,虽然它不像Java或C#那样拥有传统的类和实例机制,但它的面向对象编程能力仍然非常强大。JavaScript的核心在于对象、原型和隐式继承,这些都是理解其面向对象特性的重要概念。 ...

Global site tag (gtag.js) - Google Analytics