7.1递归

  经典递归例子

function factorial(num){
if(num <= 1){
return 1;
}else{
return num * factorial(num - 1);
}
}
var a = factorial; //①
factorial = null; //②
alert(a(3)); // ③ factorial is not a function
//原因 栈内存中存放一个factorial变量 指向堆内存中的函数体 第①句代码 执行后 变量a 亦指向 堆内存中的函数体 第③句代码执行后 factorial 变量 不再指向堆内存中的函数体 而执行第③句代码时候 函数体内部调用了 factorial变量 此时的factorial已经为null 所以提示错误 //改造 arguments.callee函数 是一个指向正在运行的函数的指针 因此采用此方式可以避免 因名称更换导致的错误 此方式不适用严格模式
function factorial1(num){
if(num <= 1){
return 1;
}else{
return num * arguments.callee(num - 1);
}
}
var b = factorial1;
factorial1 = null;
alert(b(3)); // 6 // 命名函数表达式
var factorial2 = (function f(num){
if(num <= 1){
return num;
}else{
return num * f(num - 1);
}
}); var c = factorial2;
factorial2 = null;
alert(c(3)); // 6

7.2 闭包------是指有权访问另一个函数作用域中的变量的函数      个人理解  闭包就是函数A体内返回B函数 ,B函数在外部环境执行时还依赖函数A的作用域链(无关于执行环境而依赖定义的环境)

function a(x){
return function b(y){
return x + y ;
}
}
var a1 = a(5); //①
var b1 = a1(5); //②
console.log(b1); //10 代码①处 执行时 传入变量x为5 代码②则a1引用函数b 然后再传入5 给a1 实际执行a函数内返回的b函数 此时b函数依旧能访问a函数内部的变量x 所以结果 为10

闭包的副作用------闭包只能取得函数体内变量的最后一个值,如下示例

function createFunctions1(){
var result = new Array();
for(var i=0; i< 10; i++){
result[i] = function(){
return i;
}
}
return result;
} console.log(createFunctions1()[5]()); //
//============改造==============
function createFunctions2(){
var result = new Array();
for(var i=0; i< 10; i++){
result[i] = function(num){
return function(){
return num;
}
}(i);
}
return result;
} console.log(createFunctions2()[5]()); //

改造后并没有直接把闭包赋值给数组而是采用匿名函数的方式,并且立即执行这个匿名函数,返回匿名函数内部的闭包 得以访问每个参数的值

7.2 .1关于this对象  --- this对象通常指的是整个函数执行环境, 而函数做为某个对象的方法调用时this则等于那个对象,由于闭包和匿名函数具有全局性 因此this对象通常指向window对象---如果以call或者apply去改变函数执行环境,那么this就指向其他对象

7.2.2 内存泄漏  --- IE9 之前的版本采用的是引用计数的方式回收内存  ,而闭包是一个保留函数运行结果的全局变量,因此如果在IE9之前的浏览器内运行使用了HTML元素对象的引用,那么意味着该对象无法被销毁

7.3 模仿块级作用域

JS中没有块级作用域的概念,因此块语句中定义的变量,实际上是包含在整个函数体内的,js解析器不会告知是否多次声明了同一变量(不过,会执行变量的初始化)如下示例

function output1(){
for(var i=0; i< 2; i++){
continue;
}
var i;
console.log(i);
}
output1(); //2 访问了for循环体内的执行结果 所以等于2 function output2(){
for(var i=0; i< 2; i++){
continue;
}
console.log(i);//2 访问了for循环体内的执行结果 所以等于2
var i = 1; //对变量进行初始化
console.log(i); //
}
output2();

匿名函数可以模仿块级作用域来避免这样的命名冲突--适合大型项目中采用    此方式在执行完内部的匿名函数后内存会被释放掉  因此访问 i 的时候出错

//模仿块级作用域
function output3(){
(function(){
for(var i=0; i< 2; i++){
continue;
}
})(); console.log(i);// Uncaught ReferenceError: i is not defined
}
output3();

这种技术常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数,

7.4 私有变量 -------严格的说 js中没有私有成员的概念;所有对象属性都是公有的, 但是有私有变量的概念,任何在函数内部定义的变量,都可以认为是私有变量,因为不能在函数外部访问此变量 私有变量包括函数参数,局部变量和函数内部定义的其他函数

能够访问私有变量和私有函数的方法称之为特权方法 -- 如下示例:在构造函数内部定义了所有的私有变量和函数,然后创建来可以访问这些私有成员的特权方法  !

function MyObject(){
var privateName = 'zhangsan';
var privateFunction = function(){
return false;
}
this.publicFunction = function(){
console.log(privateName);
return privateFunction();
}
} var person = new MyObject();
console.log(person.publicFunction()); // zhangsan ; false;

7.4.1静态私有变量-------构造函数内部定义特权方法的缺点,就是必须使用构造函数模式来达到这个目的,而构造函数模式的缺点则是针对每个实例都会创建通用的方法,如果对象过多则会占用大量内存,基于此问题可以采用静态私有变量来避免这个问题

(function(){
var privateName = 'zhangsan';
var privateFunction = function(){
return false;
};
MyObject = function(){}; //注意此处未使用var声明 因此MyObject是一个全局变量
MyObject.prototype.publicFunction = function(){
console.log(privateName);
return privateFunction();
};
})();
var person = new MyObject();
console.log(person.publicFunction()); // zhangsan ; false;

7.4.2 模块模式-为单例创建私有变量和特权方法 

//js中单例的定义是以字面量来创建的
var singleton = {
name : 'zhangsan',
method : function(){
return name;
}
}
console.log(singleton.method()); // zhangsan
//模块模式通过为单例添加私有变量和特权方法使其增强
var singleton = function(){
var privateName = 'zhangsan';
function privateFunction(){
return privateName;
}
return {
publicProperty : true,
publicMethod : function(){
return privateFunction();
}
};
}(); console.log(singleton.publicProperty); //true
console.log(singleton.publicMethod()); // zhangsan

7.4.3  增强的模块模式 -----此模式适用于单例必须是某种类型的实例,同时还必须添加其他的属性或方法对其加强

function CustomType(){
this.age = 18;
};
var singleton = function(){
var privateName = 'zhangsan';
function privateFunction(){
return privateName;
};
var Object = new CustomType();
Object.publicProperty = true;
Object.publicMethod = function(){
return privateFunction();
};
return Object;
}();
console.log(singleton.age); // 18 原实例中的年龄
console.log(singleton.publicProperty); //true 增强的属性
console.log(singleton.publicMethod()); // zhangsan 增强的方法

小结:   使用函数表达式可以无需对函数命名,从而实现动态编程,匿名函数也称拉达姆函数  !

函数表达式不同于函数声明,函数声明要求有名字,而函数表达式不需要,没有名字的函数表达式也叫做匿名函数

递归函数应该始终使用arguments.callee来递归调用自身,而不要使用函数名称;因为函数名称可能会改变

函数内部定义了其他函数,就创建了闭包。闭包有权访问包含函数内部的所有变量 ,闭包的作用域链上包含这它自身的作用域,函数的作用域和全局作用域 ,通常函数的作用域以及其中所有变量都会在函数执行完毕后进行销毁,但是由于闭包对函数的引用,这个函数的作用域将一直保存直到闭包不存在为止;

块级作用域 --创建并且立即调用一个函数,这样既可以执行函数,又不会在内存中留下函数的引用,其函数内部所有变量都会立即销毁

 

 

   

JAVASCRIPT高程笔记-------第 七章 函数表达式的更多相关文章

  1. JAVASCRIPT高程笔记-------第五章 引用类型

    一.Object类型 1.1创建方式 ①new关键字 : var person = new Oject(); ②给定直接量: var person = { name : "zhangsan& ...

  2. 第七章 函数表达式和函数声明,关于this对象 ,私有作用域(function(){})() ,私有变量和特权方法

    一:函数表达式和函数声明 1:函数声明和函数表达式的区别 ①函数声明不需要分号结尾 ②函数声明有函数提升的特点 ③函数声明后面不能跟圆括号直接调用,因为javascript将function关键字当作 ...

  3. JavaScript基础笔记(五) 函数表达式

    函数表达式 一.闭包 概念:闭包是指有权访问另一个函数作用域中变量的函数. function createCompareFun(propertyName) { return function (obj ...

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

      闭包 有权访问另一个函数作用域中的变量的函数 匿名函数 函数没有名字 少用闭包 由于闭包会携带包含它的函数的作用域,因此会比其它函数占用更多的内存.过度使用闭包可能会导致内存占用过多,我们建议读者 ...

  5. JavaScript学习笔记(七)——函数的定义与调用

    在学习廖雪峰前辈的JavaScript教程中,遇到了一些需要注意的点,因此作为学习笔记列出来,提醒自己注意! 如果大家有需要,欢迎访问前辈的博客https://www.liaoxuefeng.com/ ...

  6. javascript高程笔记-------第四章 变量、作用域和内存问题

    首先JavaScript中的变量分为基本类型和引用类型. 基本类型就是保存在栈内存中的简单数据段,而引用类型指的是那些保存在堆内存中的对象. 1.参数传递 javascript中所有参数的传递都是值传 ...

  7. JAVASCRIPT高程笔记-------第六章 面向对象的程序设计

    理解对象的概念  js中的对象与其他 编程语言中的类不一样  ECMAscript 没有类的概念      ECMA-262 把对象定义为 “无序属性的集合,其属性可以包含基本值,对象或者函数”   ...

  8. Android群英传笔记——第七章:Android动画机制和使用技巧

    Android群英传笔记--第七章:Android动画机制和使用技巧 想来,最 近忙的不可开交,都把看书给冷落了,还有好几本没有看完呢,速度得加快了 今天看了第七章,Android动画效果一直是人家中 ...

  9. JVM学习笔记-第七章-虚拟机类加载机制

    JVM学习笔记-第七章-虚拟机类加载机制 7.1 概述 Java虚拟机描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被 ...

随机推荐

  1. Annotation研究的一些学习资料

    转自chanyinhelv原文Annotation研究的一些学习资料 下面是我最近对Annotation研究的一些学习资料,收集于此,供大家学习之用. 一.Annotation要素类介绍 在GeoDa ...

  2. 我眼中的c++编程总结-20150602

    断断续续的学习了非常多东西,有51.Avr.ARM.PLC.C\C++.C#.TB.MC.mql4.linux....等等,近乎填鸭或者囫囵吞枣的.甚至饿狼般的扑到里面,慢慢的积累和理解中,非常多知识 ...

  3. php字符串转时间戳

    PHP 提供了函数可以方便的将各种形式的日期转换为时间戳,该类函数主要是: strtotime():将任何英文文本的日期时间描述解析为时间戳. mktime():从日期取得时间戳. strtotime ...

  4. php如何实现把多平台文件中所有的行合成一行?

    php如何实现把多平台文件中所有的行合成一行? 一.总结 1.str_replace中的数组替换:str_replace(array("/r","/n",&qu ...

  5. 自己动手编写一个VS插件(八)

    作者:朱金灿 来源:http://blog.csdn.net/clever101 利用业余时间继续开发一个VS插件.我要开发的插件是一个代码库插件,主要是用于积累我平时要使用的代码.在之前我已经实现了 ...

  6. 检索01-c#中基本数据类型和引用类型的区别

    1.基本定义 基本数据类型包括:整型.浮点型.字符型.结构体.布尔型.日期时间.枚举类型等 引用类型包括:字符串.类.数组.接口等 堆定义:是一种特殊的树形数据结构,每个结点都有一个值,一般由程序员分 ...

  7. Oracle数据库零散知识02

    15,函数的创建,要求必须有返回值,必须在语句中调用,需要多个返回值时,使用out参数类型,在user_procedures表中查询属性,在user_source表中查询源代码,创建示例: CREAT ...

  8. js声明json数据,打印json数据,遍历json数据,转换json数据为数组

    1.js声明json数据: 2.打印json数据: 3.遍历json数据: 4.转换json数据为数组; //声明JSON var json = {}; json.a = 1; //第一种赋值方式(仿 ...

  9. Sitecore

    Sitecore 功能最强大.最丰富的企业级 .NET 网站内容管理系统.包含的功能如下所述: 内容编辑和会话中的个性化 用于预览访客所看到的网站内容的体验浏览器 设备和地理位置 IP 检测(需要额外 ...

  10. 【codeforces 787A】The Monster

    [题目链接]:http://codeforces.com/contest/787/problem/A [题意] 把b一直加a->得到x 把d一直加c->得到y 然后问你x和y可不可能有相同 ...