「JavaScript 语言精粹」读书笔记--函数
函数对象
JavaScript
中函数就是对象. 函数对象连接到Function.prototype
.
当把一个函数当作构造函数(使用new
关键字)使用时, 新创建的对象的原型就是该函数的prototype
对象. 我们可以通过给prototype
设置属性而达到让该类对象拥有同样的公共属性的目的.
新创建的对象有一个__proto__
属性, 指向该函数的prototype
对象.
函数字面量
函数对象通过函数字面量来创建. 函数字面量可以出现在任何允许表达式出现的地方, 甚至可以被定义在函数内部.
内部函数处理可以访问自己的参数和变量, 他也能自由访问把它嵌套在其中的父函数的参数与变量. 通过函数字面量创建的函数对象包含一个连接到外部上下文的连接, 叫做闭包.
|
|
调用
每个函数除了声明的变量外, 还会接收两个附加的参数this
和arguments
.
调用运算符是跟在任何产生一个函数值的表达式之后的一对圆括号. 这就解释了立即执行函数的写法. 圆括号内包含参数. 参数个数不会导致运行时错误, 多余参数会被忽略, 参数缺失会被替换为undefined
.
方法调用模式
当一个函数被保存为一个对象的属性时, 称之为方法
.
这种模式下this
参数被绑定到该对象.
函数调用模式
当一个函数不是一个对象的属性时, 他就是被当作函数来调用的.
这种模式下this
被绑定到全局对象. 作者认为这是一个语言设计上的错误, 应该将其绑定到外部函数的this
变量. 我们可以这样做:
|
|
构造函数调用模式
使用new
来调用一个函数时, 就会创建一个连接到该函数的prototype
成员的新对象, 同时, this
被绑定到这个新对象上.
|
|
Apply
调用模式
apply
方法让我们构建一个参数数组传递给调用函数. 同时, 也可以指定this
的值.
该方法有两个参数:
- 第一个: 绑定给
this
的值 - 第二个: 参数数组
参数
前面提到过arguments
参数, 函数可以通过访问此参数以访问所有参数, 包括多余参数. 然而, 因为语言的设计错误, 该参数只是一个"类似数组"的对象, 它拥有一个length
属性, 但没有任何数组的方法.
返回
使用return
关键字返回, 如果没有指定, 则返回undefined
. 构造函数调用时, 如果返回值不是一个对象, 则返回this
.
异常
抛出:
|
|
捕获:
|
|
一个try
语句只会有一个捕获异常的代码块, 如果有多种异常的情况, 只有通过name
属性判断.
闭包
通过函数字面量创建的函数对象包含一个连接到外部上下文的连接, 叫做闭包.
因为JavaScript
是一个函数式语言, 所以支持返回一个函数. 这样将会导致内部函数比它的外部函数拥有更长的生命周期. 这一特性也让创建私有变量成为可能.
|
|
再来看一个糟糕的例子及其改进:
|
|
这个函数的目的是点击一个节点时, 弹出对话框显示节点的序号. 而这个函数的效果却是每次显示节点的数目.
原因在于, 创建onclick
函数时, 函数引用的变量i
属于add_the_handlers
方法, 而i
一直在改变, 直到变为nodes.length
. 所以, 当所有的onclick
方法创建完成后, 引用的i
实际上是一个变量, 值为nodes.length
.
|
|
这个改进的方法就能达到目的, 原因在于, 返回给onclick
的函数是helper
的内部函数, 其引用的i
是helper
函数的i
, 覆盖了外部的add_the_handlers
的i
. 所以, 当循环进行时, helper
中的i
因为是形参, 而不会收到add_the_handlers
中的i
的影响.
级联
其实这是一个技巧.
多数的setter
方法往往不需要返回任何内容, 这时在JavaScript
中, 函数将会返回undefined
. 如果我们需要对一个对象设置很多值, 不得不写成:
|
|
如果我们让这样的函数返回this
, 就可以启动级联
, 情况就大不一样.
|
|