位置: 编程技术 - 正文

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

发布时间:2024-02-27
6、执行环境和作用域 (1)执行环境(execution context):所有的JavaScript代码都运行在一个执行环境中,当控制权转移至JavaScript的可执行代码时,就进入了一个执行环境。活动的执行环境从逻辑上形成了一个栈,全局执行环境永远是这个栈的栈底元素,栈顶元素就是当前正在运行的执行环境。每一个函数都有自己的执行环境,当执行流进入一个函数时,会将这个函数的执行环境压入栈顶,函数执行完之后再将这个执行环境弹出,控制权返回给之前的执行环境。 (2)变量对象(variable object):每一个执行环境都有一个与之对应的变量对象,执行环境中定义的所有变量和函数就是保存在这个变量对象中。这个变量对象是后台实现中的一个对象,我们无法在代码中访问,但是这有助于我们理解执行环境和作用域相关概念。 (3)作用域链(scope chain):当代码在一个执行环境中运行时,会创建由变量对象组成的一个作用域链。这个链的前端,就是当前代码所在环境的变量对象,链的最末端,就是全局环境的变量对象。在一个执行环境中解析标识符时,会在当前执行环境相应的变量对象中搜索,找到就返回,没有找到就沿着作用域链一级一级往上搜索直至全局环境的变量对象,如果一直未找到,就抛出引用异常。 (4)活动对象(activation object):如果一个执行环境是函数执行环境,也将变量对象称为活动对象。活动对象在最开始只包含一个变量,即arguments对象(这个对象在全局环境的变量对象中不存在)。   这四个概念虽然有些抽象,但还是比较自然的,可以结合《JavaScript高级程序设计(第3版)》中的一个例子来细细体会一下: 这里的整个过程是: (1)进入全局环境,创建全局变量对象,将全局环境压入栈顶(这里也是栈底)。根据前面的关于声明提升的结论,这里创建全局变量对象可能的一个过程是,先创建全局变量对象,然后处理函数声明设置属性changeColor为相应函数,再处理变量声明设置属性color为undefined。 (2)执行全局环境中的代码。先执行color变量初始化,赋值为'blue',再调用changeColor()函数。 (3)调用changeColor()函数,进入到changeColor函数执行环境,创建这个环境相应的变量对象(也就是活动对象),将这个环境压入栈顶。创建活动对象可能的一个过程是,先创建活动对象,处理内部函数声明设置属性swapColors为相应函数,处理函数参数创建活动对象的属性arguments对象,处理内部变量声明设置属性anotherColor为undefined。 (4)执行changeColor()函数代码。先执行anotherColor初始化为'red',再调用swapColors()函数。 (5)调用swapColors()函数,进入到swapColors函数执行环境,创建相应的变量对象(活动对象),将swapColors执行环境压入栈顶。这里创建活动对象可能的一个过程是,先创建活动对象,处理函数参数,将形式参数作为活动对象的属性并赋值为undefined,创建活动对象的属性arguments对象,并根据实际参数初始化形式参数和arguments对应的值和属性(将属性color1和arguments[0]初始化为'white',由于没有第二个实际参数,所以color2的值为undefined,而arguments的长度只为1了),处理完函数参数之后,再处理函数内部变量声明,将tempColor作为活动对象的属性并赋值为undefined。 (6)执行swapColors()函数代码。先给tempColor初始化赋值,然后实现值交换功能(这里color和anotherColor的值都是沿着作用域链才读取到的)。 (7)swapColors()函数代码执行完之后,返回undefined,将相应的执行环境弹出栈并销毁(注意,这里会销毁执行环境,但是执行环境相应的活动对象并不一定会被销毁),当前执行环境恢复成changeColor()函数的执行环境。随着swapColor()函数执行完并返回,changeColor()也就执行完了,同样返回undefined,并将changeColor()函数的执行环境弹出栈并销毁,当前执行环境恢复成全局环境。整个处理过程结束,全局环境直至页面退出再销毁。   作用域链也解释了为什么函数可以在内部递归调用自身:函数名是函数定义所在执行环境相应变量对象的一个属性,然后在函数内部执行环境中,就可以沿着作用域链向外上溯一层访问函数名指向的函数对象了。如果在函数内部将函数名指向了一个新函数,递归调用时就会不正确了: 关于作用域和声明提升,再看一个例子: 这里最不直观的可能是第3行输出undefined,因为在全局中已经定义过name了,不过按照上面解析的步骤去解析一次,就可以得出正确的结果了。另外强调一下,在ECMAScript中只有全局执行环境和函数执行环境,相应的也只有全局作用域和函数作用域,没有块作用域——虽然有块语句。 对于作用域链,还可以使用with、try-catch语句的catch块来延长: &#;使用with(obj){}语句时,将obj对象添加到当前作用域链的最前端。 &#;使用try{}catch(error){}语句时,将error对象添加到当前作用域链的最前端。   插了一段较为抽象的概念,希望不至于影响整个阅读的流畅,事实上,我在这里还悄悄的绕过了一个称为“闭包”的概念,关于函数与闭包,在下篇文章中再详细叙述。 7、函数内部对象与this   对于面向对象语言的使用者来说,this实在是再熟悉不过了,不就是指向构造函数新创建的对象吗!不过,在ECMAScript中,且别掉以轻心,事情没有那么简单,虽然在使用new操作符调用函数的情况下,this也的确是指向新创建的对象,但这只是指定this对象值的一种方式而已,还有更多的方式可以指定this对象的值,换句话说,this是动态的,是可以由我们自己自由指定的。 (1)全局环境中的this   在全局环境中,this指向全局对象本身,在浏览器中也就是window,这里也可以把全局环境中的this理解为全局执行环境相应的变量对象,在全局环境中定义的变量和函数都是这个变量对象的属性: 如果在自定义函数中要引用全局对象,虽然可以直接使用window,但更好的方式则是将全局对象作为参数传入函数,这是在JS库中非常通用的一种方式: 这种方式兼容性更好(ECMAScript的实现中全局对象未必都是window),在压缩时,也可以将global简化为g,而不用使用window了。 (2)函数内部属性this   在函数环境中,this是一个内部属性对象,可以理解成函数对应的活动对象的一个属性,而这个内部属性的值是动态的。那this值是怎么动态确定的呢? &#;使用new调用时,函数也称为构造函数,这个时候函数内部的this被指定为新创建的对象。 需要注意区分一下函数执行环境中定义的属性(也即活动对象的属性)和this对象的属性,在使用数组元素方式调用函数时,函数内部this指向数组本身,因此上例最后输出undefined。 &#;作为一般函数调用时,this指向全局对象。 &#;作为对象的方法调用时,this指向调用这个方法的对象。   看下面的例子: 这里函数对象本身是匿名的,是作为person对象的一个属性,当作为对象属性调用时,this指向了对象,当把这个函数赋给另一个函数然后调用时,是作为一般函数调用的,this指向了全局对象。这个例子充分说明了“函数作为对象的方法调用时内部属性this指向这个调用对象,函数作为一般函数调用时内部属性this指向全局对象”,也说明了this的指定是动态的,是在调用时指定的,而不管函数是单独定义的还是作为对象方法定义的。也正是因为函数作为对象的方法调用时this指向这个调用对象,所以在函数内部返回this时才能够延续调用对象的下一个方法——也就是链式操作(jQuery的一大特色)。 &#;使用apply()、call()或bind()调用函数时,this指向第一个参数对象。如果没有传入参数或传入的是null和undefined,this指向全局对象(在ES5的严格模式下会设为null)。如果传入的第一个参数是一个简单类型,会将this设置为相应的简单类型包装对象。 上面示例中列出的都是一些常见情况,没有列出第一个参数为null或undefined的情况,有兴趣的朋友可以自行测试。关于this值的确定,在原书中还有一个例子: 第1个是正常输出,第2个(object.getName)与object.getName的效果是相同的,而第3个(object.getName=object.getName)最终返回的是函数对象本身,也就是说第3个会作为一般函数来调用,第4个则先是调用getNameFunc这个方法,返回一个函数,然后再调用这个函数,也是作为一般函数来调用。 8、函数属性和方法   函数是一个对象,因此也可以有自己的属性和方法。不过函数属性和方法与函数内部属性很容易混淆,既然容易混淆,就把它们放一起对照着看,就好比一对双胞胎,不对照着看,不熟悉的人是区分不了的。   先从概念上来区分一下: (1)函数内部属性:可以理解为函数相应的活动对象的属性,是只能从函数体内部访问的属性,函数每一次被调用,都会被重新指定,具有动态性。 (2)函数属性和方法:这是函数作为对象所具有的特性,只要函数一定义,函数对象就被创建,相应的属性和方法就可以访问,并且除非你在代码中明确赋为另一个值,否则它们的值不会改变,因而具有静态性。有一个例外属性caller,表示调用当前函数的函数,也是在函数被调用时动态指定,在《JavaScript高级程序设计(第3版)》中也因此将caller属性和函数内部属性arguments、this一起讲解,事实上,在ES5的严格模式下,不能对具有动态特性的函数属性caller赋值。   光从概念上区分是非常抽象的,也不是那么容易理解,再把这些属性列在一起比较一下(没有列入一些非标准的属性,如name): 类别名称继承性说明备注函数内部属性this-函数据以执行的环境对象和一般面向对象语言有很大区别arguments-

表示函数实际参数的类数组对象

arguments本身也有自己的属性:length、callee和caller

1、length属性表示实际接收到的参数个数

2、callee属性指向函数对象本身,即有:

  fn.arguments.callee === fn

3、caller属性主要和函数的caller相区分,值永远都是undefined

函数属性caller否调用当前函数的函数虽然函数一定义就可访问,但是不在函数体内访问时永远为null,在函数体内访问时返回调用当前函数的函数,在全局作用域中调用函数也会返回nulllength否函数形式参数的长度就是定义函数时命名的参数个数prototype否函数原型对象原型对象是ECMAScript实现继承的基础constructor是继承自Object,表示创建函数实例的函数,也就是Function()值永远是Function,也就是内置的函数Function()函数方法apply否调用函数自身,以(类)数组方式接受参数

这三个方法主要作用是动态绑定函数内部属性this

1、apply和call在绑定之后会马上执行

2、bind在绑定之后可以在需要的时候再调用执行

call否调用函数自身,以列举方式接受参数bind否绑定函数作用域,ES5中新增toLocalString覆盖

覆盖了Object类型中的方法,返回函数体

不同浏览器实现返回可能不同,可能返回原始代码,也可能返回去掉注释后的代码

toString覆盖valueOf覆盖hasOwnProperty是直接继承自Object类型的方法,用法同ObjectpropertyIsEnumerable是isPropertyOf是

  函数属性和方法,除了从Object继承而来的属性和方法,也包括函数本身特有的属性和方法,用的最多的方法自然就是上一小节说的apply()、call(),这两个方法都是用来设置函数内部属性this从而扩展函数作用域的,只不过apply()扩展函数作用域时是以(类)数组方式接受函数的参数,而call()扩展函数作用域时需要将函数参数一一列举出来传递,看下面的例子:

不过需要强调的是:apply和call的主要作用还是在于扩展函数作用域。apply和call在扩展作用域时会马上调用函数,这使得应用中有了很大限制,因此在ES5中新增加了一个bind()函数,这个函数也用于扩展作用域,但是可以不用马上执行函数,它返回一个函数实例,将传入给它的第一个参数作为原函数的作用域。它的一个可能的实现如下: 这里涉及了一个闭包的概念,明天再继续。

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

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

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

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

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

JavaScript高级程序设计(第3版)学习笔记 内建js对象 内建对象就好比是JDK中的类库,开发者可以直接拿来使用,这极大的方便了常见的编程任务。这篇文章就来浏览一下主要的内建对象,当然,我们并不

标签: javascript高级程序设计最新版

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

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

下一篇:JavaScript高级程序设计(第3版)学习笔记9 js函数(下)(javascript高级程序设计第五版 pdf下载)

  • 增值税税率变化时间节点
  • 支付货款的会计凭证怎么做
  • 银行端查询缴税凭证怎么盖章
  • 年度财务报表和季度财务报表一样吗
  • 开票金额为什么会多出一分钱
  • 天猫国际的店铺是正品吗 感觉很便宜
  • 1%是什么税
  • 单位发放中秋月饼价值有规定吗
  • 新的企业所得税暂行条例
  • 亏损企业能不能无常捐赠
  • 中外合作合资
  • 未开票收入已报税怎么办
  • 借款转资本公积怎么算税
  • 收到国外的服务费怎么开票
  • 哪些费用应该计税
  • 什么时候计提资本成本
  • 代理进出口公司营销方式
  • 给员工发的慰问短信
  • 筹备期间的开办企业是指
  • 营改增房租增值税税率
  • 银行汇票超期退回怎么办
  • 已经计提的税金怎么做账
  • 设备租赁公司怎么复制赚钱
  • 报销冲借款是什么意思
  • 预存500抵扣1000是几折活动?
  • 发票认证平台上不去
  • php实验步骤
  • wcu.exe是什么
  • php字符串函数有哪些
  • PHP:Memcached::__construct()的用法_Memcached类
  • php网页安全认证是什么
  • 设备拆修痕迹影响大吗
  • 税后现金流入
  • 净资产收益率的概念
  • 季报表利润表本月怎么填
  • vscode+live server——更改端口号——基础积累
  • 销售费用期末余额
  • vue有哪些方法
  • tf club下载
  • php获取位置
  • 公务交通通讯补贴
  • 不动产物权归属和内容的根据是什么?
  • 织梦怎么改文字
  • 停工期间工资支付标准
  • 商场账务
  • 应付账款转收入摘要怎么写
  • 发票金额和付款金额差几毛钱
  • 公司做的形象墙效果图
  • 汽车加油费属于交通费用吗
  • 小企业会计准则2023电子版
  • 以前年度费用科目入错 不影响以前年度利润的账务处理
  • 资产评估资产如何入帐
  • 没有对公业务的银行
  • 财政返还什么意思
  • 做假账本怎么判
  • 汽车属于固定资产吗?如何计提折旧
  • innodb_sys_tables
  • sql语句查询去重
  • sqlserver合并脚本工具
  • mysql查询两个表的数据
  • xp系统怎么连接电脑
  • win2003开机蓝屏
  • windows10x预览版
  • 没有协议盒可以设置协议吗
  • eclipse怎么创建安卓
  • jquery简单例子
  • Cocos2dx3.2 CrazyTetris 单线裁剪 对于判断消除的思考(一)
  • listview的item
  • angular重新渲染组件
  • sticky memo widget
  • jQuery中trigger()与bind()用法分析
  • 移动move命令的操作步骤是
  • oracle批处理语句
  • node.js的安装步骤
  • Javascript字符串出现次数
  • 河北地税代收工作怎么样
  • 房地产预缴土增值税
  • 誊抄什么意思
  • 车船税与船舶吨税法律制度ppt
  • 江苏盐在什么地方
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号