位置: 编程技术 - 正文

JavaScript高级程序设计(第3版)学习笔记7 js函数(上)(javascript高级程序设计pdf百度云)

发布时间:2024-02-27
变量类型   在说函数之前,先来说说变量类型。 1、变量:变量在本质上就是命名的内存空间。 2、变量的数据类型:就是指变量可以存储的值的数据类型,比如Number类型、Boolean类型、Object类型等,在ECMAScript中,变量的数据类型是动态的,可以在运行时改变变量的数据类型。 3、变量类型:是指变量本身的类型,在ECMAScript中,变量类型就只有两种:值类型和引用类型。当变量的数据类型是简单数据类型时,变量类型就是值类型,当变量的数据类型是对象类型时,变量类型就是引用类型。在不引起歧义的情况下,也可以称变量的数据类型为变量类型。   那么,值类型和引用类型有什么区别呢?最主要的一个,就是当变量类型为值类型时,变量存储的就是变量值本身,而当变量类型为引用类型时,变量存储的并不是变量值,而只是一个指向变量值的指针,访问引用类型的变量值时,首先是取到这个指针,然后是根据这个指针去获取变量值。如果将一个引用类型的变量值赋给另一个变量,最终结果是这两个变量同时指向了一个变量值,修改其中一个会同时修改到另一个: 好了,关于变量类型先说到这,如果再继续到内存存储数据结构的话,就怕沉得下去浮不上来。 函数   如果说对象是房间,那么函数就是有魔幻效应的房间了。函数首先是对象,然后这个函数对象还具有很多魔幻功能…… 1、函数 (1)函数是对象   函数也是一种对象,而用于创建函数对象实例的函数就是内置的Function()函数(创建对象实例需要函数,而函数又是一种对象实例,是不是让你有了先有鸡还是先有蛋的困惑?别钻牛角尖了,只要鸡能生蛋,蛋能孵鸡就行了,谁先谁后还是留给哲学家吧),但是函数这种对象,又和一般的对象有着极大的不同,以至于对函数对象实例使用typeof时返回的不是object而是function了。 (2)函数名是指向函数对象的引用类型变量 注:关于函数名,在ES5的严格模式下,已经不允许使用eval和arguments了,当然,参数名也不能用这两个了(我想除非你是专业黑客,否则也不会使用这些作为标识符来使用吧)。 2、函数创建 (1)作为一种对象,函数也有和普通对象类似的创建方式,使用new调用构造函数Function(),它可以接受任意数量的参数,最后一个参数作为函数体,而前面的所有参数都作为函数的形式参数,前面的形式参数还可以使用逗号隔开作为一个参数传入,一般形式为: 例如: 这种方式创建函数,会解析两次代码,一次正常解析,一次解析函数体,效率会影响,但是比较适合函数体需要动态编译的情况。 (2)由于函数对象本身的特殊性,我们还可以使用关键字function来创建函数: 从上可以看到,使用function关键字创建函数也有两种方式:函数声明和函数表达式。这两种方式都能实现我们想要的效果,那他们之间有什么区别呢?这就是我们下面要讲的。 3、函数声明和函数表达式 (1)从形式上区分,在ECMA-的规范中,可以看到: 除了函数表达式的标识符(函数名)是可选的之外没有任何区别,但我们也可以从中得知:没有函数名的一定是函数表达式。当然,有函数名的,我们就只能从上下文来判断了。 (2)从上下文区分,这个说起来简单,就是:只允许表达式出现的上下文中的一定是函数表达式,只允许声明出现的上下文的一定是函数声明。举一些例子: (3)区别:我们为什么要花这么大力气来区分函数声明和函数表达式呢?自然就是因为它们的不同点了,他们之间最大的不同,就是声明会提升,关于声明提升,在前面基础语法的那一篇文章中,曾经对全局作用域中的声明提升做过讨论,我们把那里的结论复习一下: A、引擎在解析时,首先会解析函数声明,然后解析变量声明(解析时不会覆盖类型),最后再执行代码; B、解析函数声明时,会同时解析类型(函数),但不会执行,解析变量声明时,只解析变量,不会初始化。 在那里也举了一些例子来演示(回忆一下),不过没有同名称的声明例子,这里补充一下: 可以看出:不管变量声明是在前还是在后,在声明提升时都是以函数声明优先,但是在声明提升之后,由于要执行变量初始化,而函数声明不再有初始化(函数类型在提升时已经解析),因此后面输出时就成为String类型了。 上面第3行定义了一个函数,然后第7行马上调用,结果竟然不行!你该明白保持全局命名空间清洁的重要性了吧,要不然,你可能会遇到“我在代码中明明定义了一个函数却不能调用”这种鬼事情,反过来,如果你想确保你定义的函数可用,最好就是使用函数表达式来定义,当然,这样做你需要冒着破坏别人代码的风险。 还有一个问题,这里我们怎么确定变量类型是在初始化时候而不是在变量声明提升时候改变的呢?看下面的代码: 可以看到,声明提升后类型为function,并且由于没有初始化代码,最后的类型没有改变。   关于函数声明和函数表达式,还有一点需要注意的,看下面的代码: 在ECMAScript规范中,命名函数表达式的标识符属于内部作用域,而函数声明的标识符属于定义作用域。 上面是一个命名函数表达式在FireFox中的运行结果,在函数作用域内可以访问这个名称,但是在全局作用域中访问出现引用异常。不过命名函数表达式在IE9之前的IE浏览器中会被同时作为函数声明和函数表达式来解析,并且会创建两个对象,好在IE9已经修正。   除了全局作用域,还有一种函数作用域,在函数作用域中,参与到声明提升竞争的还有函数的参数。首先要明确的是,函数作用域在函数定义时不存在的,只有在函数实际调用才有函数作用域。 通过上面的输出结果,我们得出优先级:内部函数声明 > 函数参数 > 内部变量声明。   这里面的一个过程是:首先内部函数声明提升,并将函数名的类型设置为函数类型,然后解析函数参数,将传入的实际参数值赋给形式参数,最后再内部变量声明提升,只提升声明,不初始化,如果有重名,同优先级的后面覆盖前面的,不同优先级的不覆盖(已经解析了优先级高的,就不再解析优先级低的)。   说明一下,这只是我根据输出结果的推断,至于后台实现,也有可能步骤完全相反,并且每一步都覆盖前一步的结果,甚至是从中间开始,然后做一个优先级标志确定是否需要覆盖,当然,从效率上来看,应该是我推断的过程会更好。另外,全局作用域其实就是函数作用域的一个简化版,没有函数参数。   这里就不再举综合的例子了,建议将这篇文章和前面的基础语法那一篇一起阅读,可能效果会更好。关于优先级与覆盖,也引出下面要说的一个问题。 4、函数重载   函数是对象,函数名是指向函数对象的引用类型变量,这使得我们不可能像一般面向对象语言中那样实现重载: 不要奇怪第8行为什么输出NaN,因为函数名只是一个变量而已,两次函数声明会依次解析,这个变量最终指向的函数就是第二个函数,而第8行只传入1个参数,在函数内部b就自动赋值为undefined,然后与1相加,结果就是NaN。换成函数表达式,也许就好理解多了,只是赋值了两次而已,自然后面的赋值会覆盖前面的: 那么,在ECMAScript中,怎么实现重载呢?回想一下简单数据类型包装对象(Boolean、Number、String),既可以作为构造函数创建对象,也可以作为转换函数转换数据类型,这是一个典型的重载。这个重载其实在前一篇文章中我们曾经讨论过: (1)根据函数的作用来重载,这种方式的一般格式为: 这种方式虽然可行,但是很明显作用也是有限的,比如就只能重载两次,并且只能重载包含构造函数的这种情形。当然,你可以结合apply()或者call()甚至ES5中新增的bind()来动态绑定函数内部的this值来扩展重载,但这已经有了根据函数内部属性重载的意思了。 (2)根据函数内部属性来重载 这里就是利用函数内部属性arguments来实现重载的。当然,在内部重载的方式可以多种多样,你还可以结合typeof、instanceof等操作符来实现你想要的功能。至于内部属性arguments具体是什么?这就是下面要讲的。 5、函数内部属性arguments   简单一点说,函数内部属性,就是只能在函数体内访问的属性,由于函数体只有在函数被调用的时候才会去执行,因此函数内部属性也只有在函数调用时才会去解析,每次调用都会有相应的解析,因此具有动态特性。这种属性有:this和arguments,这里先看arguments,在下一篇文章中再说this。 (1)在函数定义中的参数列表称为形式参数,而在函数调用时候实际传入的参数称为实际参数。一般的类C语言,要求在函数调用时实际参数要和形式参数一致,但是在ECMAScript中,这两者之间没有任何限制,你可以在定义的时候有2个形式参数,在调用的时候传入2个实际参数,但你也可以传入3个实际参数,还可以只传入1个实际参数,甚至你什么参数都不传也可以。这种特性,正是利用函数内部属性来实现重载的基础。 (2)形式参数甚至可以取相同的名称,只是在实际传入时会取后面的值作为形式参数的值(这种情况下可以使用arguments来访问前面的实际参数): 这其实也可以用本文前面关于声明提升的结论来解释:同优先级的后面的覆盖前面的,并且函数参数解析时同时解析值。当然,这样一来,安全性就很成问题了,因此在ES5的严格模式下,重名的形式参数被禁止了。 (3)实际参数的值由形式参数来接受,但如果实际参数和形式参数不一致怎么办呢?答案就是使用arguments来存储,事实上,即便实际参数和形式参数一致,也存在arguments对象,并且保持着和已经接受了实际参数的形式参数之间的同步。将这句话细化一下来理解: &#;arguments是一个类数组对象,可以像访问数组元素那样通过方括号和索引来访问arguments元素,如arguments[0]、arugments[1]。 &#;arguments是一个类数组对象,除了继承自Object的属性和方法(有些方法被重写了)外,还有自己本身的一些属性,如length、callee、caller,这里length表示实际参数的个数(形式参数的个数?那就是函数属性length了),callee表示当前函数对象,而caller只是为了和函数属性caller区分而定义的,其值为undefined。 &#;arguments是一个类数组对象,但并不是真正的数组对象,不能直接对arguments调用数组对象的方法,如果要调用,可以先使用Array.prototype.slice.call(arguments)先转换为数组对象。 &#;arguments保存着函数被调用时传入的实际参数,第0个元素保存第一个实际参数,第1个元素保存第二个实际参数,依次类推。 &#;arguments保存实际参数值,而形式参数也保存实际参数值,这两者之间有一个同步关系,修改一个,另一个也会随之修改。 &#;arguments和形式参数之间的同步,只有当形式参数实际接收了实际参数时才存在,对于没有接收实际参数的形式参数,不存在这种同步关系。 &#;arguments对象虽然很强大,但是从性能上来说也存有一定的损耗,所以如果不是必要,就不要使用,建议还是优先使用形式参数。 经过测试,arguments和形式参数之间的同步是双向的,但是《JavaScript高级程序设计(第3版)》中第页说是单向的:修改形式参数不会改变arguments。这可能是原书另一个Bug,也可能是FireFox对规范做了扩展。不过,这也让我们知道,即便经典如此,也还是存有Bug的可能,一切当以实际运行为准。 &#;结合arguments及其属性callee,可以实现在函数内部调用自身时与函数名解耦,这样即便函数赋给了另一个变量,而函数名(别忘了,也是一个变量)另外被赋值,也能够保证运行正确。典型的例子有求阶乘函数、斐波那契数列等。 递归的算法非常简洁,但因为要维护运行栈,效率不是很好。关于递归的优化,也有很多非常酣畅漓淋的算法,这里就不深入了。   需要注意的是,arguments.callee在ES5的严格模式下已经被禁止使用了,这时候可以使用命名的函数表达式来实现同样的效果:

推荐整理分享JavaScript高级程序设计(第3版)学习笔记7 js函数(上)(javascript高级程序设计pdf百度云),希望有所帮助,仅作参考,欢迎阅读内容。

JavaScript高级程序设计(第3版)学习笔记7 js函数(上)(javascript高级程序设计pdf百度云)

文章相关热门搜索词:javascript高级程序设计电子版,javascript高级程序设计第三版,javascript高级程序设计第三版,javascript高级程序设计第五版 pdf下载,javascript高级程序设计pdf百度云,javascript高级程序设计第六版,javaScript高级程序设计有几版,javascript高级程序设计第六版,内容如对您有帮助,希望把文章链接给更多的朋友!

JavaScript高级程序设计(第3版)学习笔记8 js函数(中) 6、执行环境和作用域(1)执行环境(executioncontext):所有的JavaScript代码都运行在一个执行环境中,当控制权转移至JavaScript的可执行代码时,就进入了

JavaScript高级程序设计(第3版)学习笔记9 js函数(下) 再接着看函数——具有魔幻色彩的对象。9、作为值的函数在一般的编程语言中,如果要将函数作为值来使用,需要使用类似函数指针或者代理的方式来

JavaScript高级程序设计(第3版)学习笔记 再访js对象 1、对象再认识(1)对象属性和特性什么是属性(Property),什么是特性(Attribute),这有什么区别?我不想也不会从语义学上去区分,对于这系列文章

标签: javascript高级程序设计pdf百度云

本文链接地址:https://www.jiuchutong.com/biancheng/380511.html 转载请保留说明!

上一篇:JavaScript高级程序设计(第3版)学习笔记6 初识js对象(javascript高级程序设计pdf百度云)

下一篇:JavaScript高级程序设计(第3版)学习笔记8 js函数(中)(javascript高级程序设计最新版)

  • 自然人税收管理系统扣缴客户端
  • 年报从业人数可以填一人吗
  • 预提车间租入固定资产租金800元
  • 赠送客户的产品计入销售费用的二级科目
  • 销售方记账凭证怎么做分录
  • 业务员不拿工资怎么办
  • 材料税款抵扣
  • 从个人处借款的法律规定
  • 单次劳务费税率
  • 上报汇总和抄报是一个意思吗
  • 应税行为扣除额怎么填
  • 各地土地使用税区域差距大
  • 高新企业入库是什么意思
  • 买免税产品
  • 土地转让应交税费
  • 所得税申报怎么弥补以前年度亏损
  • 发票先入账,但发票不对
  • 材料没入库的会计分录
  • 公司筹备期的费用
  • php使用js
  • 腾达路由器默认网关
  • 如何开启系统自带杀毒软件
  • SCHDPL32.EXE - SCHDPL32是什么进程 有什么用
  • 应付债券到期偿还
  • kprcycleaner.exe是什么
  • vue router
  • 实收资本主要包括哪些
  • 嵌入式开关安装效果图
  • YOLOv5|YOLOv7|YOLOv8改各种IoU损失函数:YOLOv8涨点Trick,改进添加SIoU损失函数、EIoU损失函数、GIoU损失函数、α-IoU损失函数
  • chat的用法及短语
  • 集合框架有何好处
  • 转账支票购买办公用品一批,共计600元
  • 进项税额转出可以为负数吗
  • 应收账款资产负债表负数
  • 开发票的盘锁了
  • 企业送的购物卡怎么退回去
  • 收到汇算清缴的退税需要交税吗
  • 免税黄金什么意思
  • 预扣预缴和汇算清缴是什么意思
  • sqlserver2012开发版
  • 一般计税预缴增值税2%怎么算
  • 小规模纳税人固定资产原值含税吗
  • 实收资本是什么科目
  • 个税征税对象包括哪些
  • 什么情况下借递债券
  • 应收账款和应付账款属于什么科目
  • 营改增后可以抵扣的进项
  • 个税里的年金是指
  • 如何理解出口退税的意义
  • 已付款未认证发票怎么做账
  • 与其他企业联营
  • 增值税留抵怎么做凭证
  • 企业购买黄金该交什么税
  • 公司法人章财务章丢了怎么办
  • 会计损益类科目有哪些,期末如何结转?
  • 认缴制下实收资本可以一直为零吗
  • 累计折旧可以作为利润分配吗
  • 固定资产原值的构成内容是
  • sql语句中截取字符串
  • win7系统无法运行红警游戏
  • Win10预览版怎么变回正式版
  • xp系统如何清除所有盘的东西
  • 亲测可用抖音低价单赚派费项目
  • 联想win7笔记本怎么进入bios
  • linux确认命令
  • perl随机数
  • jquery注释有哪几种
  • 黑马程序员android移动开发基础教程
  • 最基本的实现进程是
  • javascript获取css
  • 删除cmd命令记录
  • js中的require用法
  • javascript学习指南
  • Using Django with GAE Python 后台抓取多个网站的页面全文
  • javascript怎么编写
  • 堆实现栈
  • 整理Javascript事件响应学习笔记
  • 利用jQuery实现一个时间无法显示
  • 北京国税电子税务局网址
  • 办理跨区域事项报验
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号