《JavaScript高级程序设计(第二版)》学习(5)函数表达式

声明:这类属于学习笔记,主要是摘录书中内容,比较少的整理。内容经常是跳跃的,建议您阅读书本,收益更大。



定义函数的方式有2种,第一种是函数声明,另一种是函数表达式

函数声明会提升,就是JavaScript引擎先什么都不干,先把函数声明的代码解析一下,那么你是在此之前先用还是后用就无所谓了;但是表达式就没有这种特点,必须在函数表达式之后调用才不会出错。

//这个是可以的
sayhi();
function sayhi(){
    alert("hi");
}

//这种是不行的
sayhi();
var sayhi=function(){
    alert("hi");
};

关于递归:递归因为函数名可能变化,因此一般不会使用函数名,而是使用arguments.collee(n-1)类似这样的方法,但是在严格模式下,是不能获取arguments的,因此可以这么做

//在严格模式下arguments.callee无法通过脚本访问
//可以使用如下方法来代替使用
var fac=(function f(num){
    if(num<=1){
        return 1;
    }else{
        return num*f(num-1);
    }
});

console.log(fac(5));

闭包

有权访问另一个函数作用域中的变量的函数
创建闭包的常见方式使用嵌套函数

当函数第一次被调用时,会创建一个执行环境以及相应的作用域链,并把作用域链赋值给一个特殊的内部属性[[scope]]。然后使用this,arguments和其他命名函数的值来初始化函数的活动对象。但是外部函数的活动对象处于第二位,这样一直到全局执行环境。

在后台的每个执行环境都有一个表示变量的对象——变量对象。全局环境下的变量对象始终存在,而函数内的局部环境的变量对象,在函数执行结束后就消失了。作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。

然而闭包靠内部定义的函数会将包含函数(外部函数)的活动对象添加到它的作用域链中。当外部函数(不是全局函数的话)执行结束,其执行环境的作用域链会销毁,但活动对象不会回收。

由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存,过多使用闭包可能导致内存占用过多。

其次
作用域链的配置机制引起一个闭包的副作用:
只能取得包含函数中任何变量的最后一个值。

function createFunc(){
    var result=new Array();

    for (var i=0; i<10; i++){
        result[i]=function(){
            return i;
        };
    }
    return result;
}

// 得到的函数数组里,i全都10

因为每个函数的作用域链中都保存着外部函数的活动对象,所以他们引用的是同一个变量i,当函数返回result,i的值都是10.

对此我们可以用一种办法强制让闭包符合我们的预期

function create(){
    var result=new Array();

    for(var i=0; i<10; i++){
        result[i]=function(num){
            return function(){
                return num;
            };
        }(i);//立即执行匿名函数并将结果给result
    }
    return result;
}

console.log(create());

闭包里一个经常容易造成问题的是this

匿名函数的执行环境具有全局性,因此this通常是指向window。但因为闭包编写的方式不同,这一点可能会有所不同。

var name="the window";

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

console.log(obj.getNameFunc()()); //the window
var name="the window";

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

console.log(obj.getNameFunc()()); //my object

在下面这几种特殊情况下this也可能会意外改变

    var name="the window";

    var obj={
        name:"my object",
        getNameFunc:function(){
            return this.name;
        }
    };

    console.log(obj.getNameFunc()); //the object
    var aa=(obj.getNameFunc)(); //the object
    var bb=(obj.getNameFunc=obj.getNameFunc)(); //the window
    console.log(aa+"  "+bb);

    //第一行代码和平常一样调用了对象的方法
    //第二行代码使用了立即执行
    //第三行先是执行了赋值语句,然后调用赋值结果。因为赋值表达式是函数本身
    //所以this不能得到维持,结果就返回了this.window
时间: 2024-12-17 17:48:29

《JavaScript高级程序设计(第二版)》学习(5)函数表达式的相关文章

Javascript高级程序设计——this、闭包、函数表达式

在javascript中函数声明会被提升,而函数表达式不会被提升.当函数执行时,会创建一个执行环境和相应的作用域链,然后利用arguments和其他的命名参数的值来初始化函数的活动对象,作用域链链中所有的外部活动对象都处于第二的位置. function compare(num1, num2){ if(num1 < num2){ retunr -1; } else if(num1 = num2){ retunr 0; } else(num1 > num2){ retunr 1; } } var

《JavaScript高级程序设计 第二版》理解对象

声明:这类属于学习笔记,主要是摘录书中内容,比较少的整理.内容经常是跳跃的,建议您阅读书本,收益更大. ECMA-262把对象定义为“无序属性的集合,其属性可以包含基本值,对象或者函数” 对象时一组没有特定顺序的值,每个属性或方法都有一个名字,每个名字都映射一个值. 每个对象都是基于一个引用类型创建的,这个引用类型可以是第5章讨论的原生类型,也可以是开发人员定义的类型 常规的创建对象的方法是通过Object这个内置对象来进行创建出一个实例,然后再給其添加属性和方法 var person=new

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

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

《JavaScript高级程序设计》的学习总结 二

引言:在学习JavaScript之前,我们要先学习如何在HTML中引用JavaScript,此篇总结将会详细介绍<script>元素的用法及其属性,并分析几种引用方式的优劣,以及延迟脚本和异步脚本的区别. <script>的介绍及其属性: 向HTML中插入JavaScript的只要方法使用<script>元素,这个元素由Netscape (网景公司)创造,并在Netscape Navigator 2中首先实现,后来这个元素被加入到正式的HTML规范中.HTML4.01

Javascript高级程序设计——第二章:在HTML中使用Javascript

第二章:在HTML中使用Javascript <script>元素 向HTML页面中插入Javascript的主要方法,就是使用<script>元素,<script>元素有六个属性: async:可选.表示应该立即下载脚本,但不妨碍页面的其他操作,比如下载其他资源或等待加载其他脚本,只针对外部脚本有效. defer:可选.表示脚本可以延迟到文档完全被解析和显示之后再执行.只针对外部脚本有效. src:可选.表示包含要执行代码的外部文件. type:可选.表示编写代码使用

Javascript高级程序设计——第三章:函数

函数Function 通过函数封装多条语句,在任何地方执行.javascript函数不会重载,相同名字函数,名字属于后定义的函数通过function关键词声明. function functionName(arguments){ statement; } 函数会在执行return语句后停止并退出.return语句之后的任何代码不会被执行. function say(){ return “hay”; alert("hay"); //永远不执行 } return后不带返回值的会返回unde

javascript高级程序设计---第二、三章

在HTML中引用javaScript javascript的几个属性  type async(异步加载 只适用于外部JS且IE8以上 HTML5规范 先于load执行) src defer(延迟加载 只适用于外部加载 先于load执行) 在HTML中使用外部JS代码的优点,1.便于维护 ,2.可缓存.3.适应未来. 在javascript中区分变量的大小写 比如(test 和 Text是?的两个变量) 在ECMA5中新模式,严格模式  'use strict'在js代码中加入这句话即为严格模式

读书笔记 - javascript 高级程序设计 - 第二章 在Html中使用JavaScript

1 <script>的6个属性 async  立即下载当前script标签的外部脚本 但不能影响别的 charset 没用了 defer  文档显示之后再执行脚本,只对外部脚本有效 language 没用了 src type 描述代码内容Mine类型 默认就是text/javascript 没什么用 2 在解释器对<script>元素内部的所有代码求值完毕以前 页面中的其余内容都不会被浏览器加载或显示 3 有两种script 嵌入式 外部引入式 在解析外部引入式的js文件时,页面的

JavaScript高级程序设计(第三版)学习,第一次总结

Array类型 var arr = []; arr.length; //返回数组元素个数 改变length可以动态改变数组大小 检测数组 instanceof可以检测某个对象是否是数组,限制:只能是一个网页或一个全局作用域 Array.isArray(arr); //最终确定某个值到底是不是数组,没有限制 转换方法 arr.toString(); //返回由数组每个值的字符串形式拼接而成的以逗号分隔的字符串 arr.valueOf(); //与toString方法一致 arr.toLocalSt

JavaScript高级程序设计(第三版)学习笔记20、21、23章

第20章,JSON JSON(JavaScript Object Notation,JavaScript对象表示法),是JavaScript的一个严格的子集. JSON可表示一下三种类型值: 简单值:字符串,数值,布尔值,null,不支持js特殊值:undefined 对象:一组无序的键值对 数组:一组有序的值的列表 不支持变量,函数或对象实例 注:JSON的字符串必须使用双引号,这是与JavaScript字符串最大的区别 对象 { "name":"Nicholas"