第七章 函数表达式

闭包

在一个函数内部创建一个子函数,子函数可以访问父函数作用域中的变量。

function f (propertyName) {                     //创建 f()函数时,会创建一个预先包含全局变量的作用域链,这个作用域链中包含函数f(),并把这个作用域链保存再内部的[[scope]]属性中
  return function(obj1, obj2) {               //匿名函数(子函数)把父函数(f())的活动对象添加到它自己的作用域链中。
          var value1 = obj1[propertyName];     //匿名函数被返回后,它的作用域链被初始化为包含f()函数的活动对象和全局变量对象。
          var value2 = obj2[propertyName];     //当函数执行完毕后,f()函数的活动对象(即arguments,和propertyName)不会被销毁,因为匿名函数的作用域链仍然再引用这个活动对象。
          if(value1 > value2) {                //直到匿名函数被销毁后,f()函数的活动对象才会被销毁
              return 1;
            }else if(value1 < value2) {
              return -1;
            }else {
              return 0;
            };
   };
}
var compare = f("name");                  var result = compare({name: "Nicholas"}, {name: "Grag"});
// 在全局作用域中调用f()函数时,会为函数创建一个执行环境,通过复制函数的[[scope]]属性中的对象构建起执行环境的作用域链。这里的全局变量对象(变量:compare()和函数 f())// 活动对象(f()函数的arguments, propertyName); 
 

活动对象:是在进入函数执行环境时创建的,它通过函数的arguments属性初始化

当函数被调用时,会创建一个执行环境及其相应的作用域链。使用 arguments 和其他命名参数的值来初始化函数的活动对象。在作用域链中,父函数的活动对象处于第二位,以此类推,直到全局执行环境。

 闭包的缺点:子函数会携带父函数的作用域,会比其他函数占用更多的内存。过度使用会导致内存占用过多。

this对象

在运行时基于函数的执行环境绑定的:再全局函数中,this等于window,当函数被作为某个对象的方法调用时,this等于那个对象。

var name = "the window";

var object = {
     name: "My Object",
     getNameFunc: function() {
         return function() {
             return this.name;        //函数被调用时,自动取得俩个特殊变量this和arguments,内部函数搜索这俩个变量时,只会搜索到其活动对象。不能搜索外部函数的这俩个变量。
         };
    }
};

console.log(object.getNameFunc()());
//  the window

可以把外部作用域中的this对象保存再一个闭包访问的到的变量里。就可以让this引用正确的对象了

var name = "the window";

var object = {
     name: "My Object",
     getNameFunc: function() {
         var that = this;
         return function() {
             return that.name;
         };
    }
};

console.log(object.getNameFunc()());
// My Object

模仿块级作用域

匿名函数可以用来模仿块级作用域,也称为私有作用域。

(function() {
   //这里是块级作用域
}) ();

无论再什么地方,只要临时需要一些变量,就可以使用私有作用域。

function outputNumbers(count) {
   (function() {
       for(var i=0; i < count; i++) {
           console.log(i);
          }
    }) ();
   console.log(i);     //出错
}

再匿名函数中的计数器i;再执行完毕后i就被销毁了。只所以可以访问变量count,因为它是个闭包,闭包函数能够访问包含它的函数中所有的活动对象。

私有变量

私有变量:任何在函数中定义的变量,函数的参数,函数内定义的其他函数。

特权方法: 有权访问私有变量和私有函数的公有方法。

function MyObject() {

  //私有变量和私有函数
   var privateVariable = 10;

   function privateFunction() {
         return false;
   }

  //特权方法
   this.publicMethod = function () {
        privateVariable++;
        return privateFunction();
    };
}

能够在构造函数中定义的特权方法,因为特权方法作为闭包有权访问在构造函数中定义的所有变量和函数。

静态私有变量

以这种方式创建静态私有变量会因为使用原型而增进代码复用,但每个实例都没有自己的私有变量。

(function() {
   var name = "";
   Person = function(value) {
         name = value;
   };

   Person.prototype.getName = function() {
        return name;
   };

   Person.prototype.setName = function(value) {
       name = value;
   };

}) ();

var person1 = new Person("Nicholas");
console.log(person1.getName());
person1.setName("Grag");
console.log(person1.getName());
// Nicholas
// Grag

var person2 = new Person("Michael");
console.log(person1.getName());
console.log(person2.getName());

// Michael
// Michael

模块模式

为单例创建私有变量和特权方法。单例:只有一个实例对象。

如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能够访问这些私有数据的方法,就可以使用模块模式。

var application = function () {

    //私有变量和 数组
    var components = new Array();

    //new BaseComponent()代表添加一个实例进行初始化。只是用来展示初始化不用深究
    components.push(new BaseComponent()); 

   //公有方法和属性
    return {
       getComponentCount: function () {
            return component.length;
       },

       registerComponent: function() {
            if(typeof component == "object") {
                 components.push(component);
            }
       }
   };
} ();

增强的模块模式

增强的模块模式适合: 单例必须是某种类型的实例, 同时还必须添加某些属性和方法对其加以增强的情况。

var application = function () {

    //私有变量和函数
     var  components = new Array();

    //初始化
     components.push(new BaseComponent());

    //创建application的一个局部副本
     var app  = new BaseComponent();

    //公共接口
     app.getComponentCount = function () {
         return components.length;
     };

     app.registerComponent = function(component) {
          if(typeof component == "object") {
                  components.push(component);
          }
    };
   返回这个副本
    return app;
}();
时间: 2024-10-26 02:33:10

第七章 函数表达式的相关文章

JavaScript高级程序设计(第三版)第七章 函数表达式

一种是函数声明:另一种是函数表达式. 函数声明提升: say Hi(); function say Hi(){ alert("Hi!"); }      //这个例子不会抛出错误,因为在代码执行之前会先读取函数声明. 匿名函数:var functionName=function(arg0,arg1,arg2){函数体}; sayHi();   //错误:函数还不存在 var sayHi=function(){ alert("Hi!"); }; //不要这样做    

读书笔记 - js高级程序设计 - 第七章 函数表达式

闭包 有权访问另一个函数作用域中的变量的函数 匿名函数 函数没有名字 少用闭包 由于闭包会携带包含它的函数的作用域,因此会比其它函数占用更多的内存.过度使用闭包可能会导致内存占用过多,我们建议读者只在绝对必要时再考虑使用闭包 模块模式   增强的模块模式   特权方法 有权访问私有变量的公有方法叫做特权方法 块级作用域   实现单例的特权方法  

第七章 函数

第七章  函数 7.1  函数的基础知识 要使用函数,必须完成如下工作: Ø  提供函数定义 Ø  提供函数原型 Ø  调用函数 7.1.1  函数的定义 函数总体来说可以分为两类,一类是没有返回值的,另一类是具有返回值的,两类的函数定义的格式如下 void functionName(parameterList) { statement(s) return; //可以有也可以没有 } typeName functionName(parameterList) { statement(s) retu

语法》第七章 函数

(本文为阮一峰js标准教程的学习笔记,旨在总结该教程中涉及的知识点大纲及个人所做的一些拓展,方便作为"目录"或者"大纲"复习和查漏补缺,详细内容请参见阮一峰教程原文) 第二部分 语法 ************第七章 函数************ 一.概述函数就是一段可以反复调用的代码块.函数还能接受输入的参数,不同的参数会返回不同的值.1.函数的三种声明方法1.1function命令[标准函数声明方法]function 函数名(传入参数){函数体} 1.2采用函数表

C++_第七章函数的基本知识_求阶乘的子函数_ 函数参数类型为数组_ 求数组内所有元素和、部分元素和的方法_实现了先从键盘输入到一个数组中,再用for循环取读出数组中的元素 for循环也可以用break来结束循环的

/* 第七章函数的基本知识 */ /*01)c++对于返回值有一定的限制:可以是常量.变量.指针.结构对象或表达式,但不可以是数组02)c++返回数组的方法:将数组作为结构会对象组成部分来返回03)函数遇到return则结束该函数04)如果一个函数的两房额参数类型相同,则必须分别制定每个参数的类型,而不能像声明常规变量那样,将声明组合在一起05)*/ //本代码注意double类型的写法以及double和int类型数据的转换 1 #include <iostream> 2 3 void che

javascript高级程序设计笔记(第7章 函数表达式)

7.5 小结 在JavaScript 编程中,函数表达式是一种非常有用的技术.使用函数表达式可以无须对函数命名,从而实现动态编程.匿名函数,也称为拉姆达函数,是一种使用JavaScript 函数的强大方式.以下总结了函数表达式的特点.? 函数表达式不同于函数声明.函数声明要求有名字,但函数表达式不需要.没有名字的函数表达式也叫做匿名函数.? 在无法确定如何引用函数的情况下,递归函数就会变得比较复杂:? 递归函数应该始终使用arguments.callee 来递归地调用自身,不要使用函数名——函数

7章 函数表达式

定义函数的两种方式 函数声明 function functionName(arg0, arg1,arg2){     //函数体 } //非标准的name属性 //只在Firefox.Safari.Chrome和Opera有效 alert(functionName.name);    //'functionName' 特点: 函数声明提升(执行代码之前会先读取函数声明,因此可以把函数声明放在调用它的语句后面): 不能出现在判断.循环等位置. 函数表达式 //匿名函数(拉姆达函数) var fun

JavaScript高级程序设计:第七章 - 函数

六.函数表达式 //把函数当成值来使用的情况下,都可以使用匿名函数 递归 //递归函数是在一个函数通过名字调用自身的情况下构成的 //使用函数声明来定义递归函数可能会出现问题 //这是一个经典的递归阶乘函数 function factorial(num) { if (num<1){ return 1; }else{ return num * factorial(num-1); } } //使用函数声名来定义该递归函数时,函数名和函数体会产生耦合. //当其他指针指向该函数体的时候,由于执行ano

闭包与私有域[第7章-函数表达式 笔记1]

闭包 看如下示例: function createComparisonFunction(propertyName) { return function(object1, object2){ var value1 = object1[propertyName]; var value2 = object2[propertyName]; if (value1 < value2){ return -1; } else if (value1 > value2){ return 1; } else { r