当前位置: 首页 > news >正文

JAVASCRIPT高程笔记-------第 七章 函数表达式

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]());  //10
//============改造==============
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]());  //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); //1
}
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来递归调用自身,而不要使用函数名称;因为函数名称可能会改变

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

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

 

 

 

 

 

 

 

 

 

 

 

 

   

 

转载于:https://www.cnblogs.com/shenwenbo/p/7853827.html

相关文章:

  • 适应性超强的focus
  • 内存泄漏
  • 首页列表显示全部问答,完成问答详情页布局
  • POJ 2057 The Lost House 树形DP+贪心
  • JAVA Http Basic auth
  • 如何两个栈实现队列?两个队列实现栈?
  • Java之字符流操作-复制文件
  • 判断是否长按某一键
  • 【Android】封装一个简单好用的打印Log的工具类
  • centos7 防火墙 开启端口 并测试
  • 设计模式
  • IDA.快捷键_ZC收集
  • 直接从google中引入jquery.js
  • Sql注入攻击
  • linux下vsftpd客户端时间不一致问题
  • 《Java编程思想》读书笔记-对象导论
  • 【347天】每日项目总结系列085(2018.01.18)
  • 230. Kth Smallest Element in a BST
  • Apache的基本使用
  • exports和module.exports
  • in typeof instanceof ===这些运算符有什么作用
  • JavaScript 奇技淫巧
  • Java精华积累:初学者都应该搞懂的问题
  • React+TypeScript入门
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • SAP云平台里Global Account和Sub Account的关系
  • Spark学习笔记之相关记录
  • vue中实现单选
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 聊聊sentinel的DegradeSlot
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • 一起参Ember.js讨论、问答社区。
  • 移动端唤起键盘时取消position:fixed定位
  • python最赚钱的4个方向,你最心动的是哪个?
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • 容器镜像
  • 如何在招聘中考核.NET架构师
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • $L^p$ 调和函数恒为零
  • (2)(2.10) LTM telemetry
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (二)fiber的基本认识
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (论文阅读笔记)Network planning with deep reinforcement learning
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (转载)Google Chrome调试JS
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...