一、JavaScript 函数定义
通过 function 关键词定义。
1、函数声明
function functionName(parameters) { 要执行的代码 }
被声明的函数不会直接执行,而是在被调用时执行。一般不以分号(用于分隔可执行的 JavaScript 语句)结尾。
2、函数表达式定义
var x = function (a, b) {return a * b}; //函数表达式在变量x中保存,此后x可作为函数(或值)使用。称之为匿名函数。
3、Function() 构造器——内建 JavaScript 函数构造器
var myFunction = new Function("a", "b", "return a * b"); //等同于var myFunction = function (a, b) {return a * b};
var x = myFunction(4, 3);
一般避免使用new关键词。
4、函数提升
Hoisting 应用于变量声明和函数声明。但使用表达式定义的函数不会被提升。
5、自调用函数
函数表达式可作为自调用,函数声明不可自调用。
函数表达式自动执行自调用,只需要在表达式后加()。若自调用函数声明,则需将整个函数声明用圆括号括起来(表示它是一个函数表达式),再添加()。
6、函数是对象
typeof 运算符为函数返回 "function",但最好将函数描述为对象,有属性和方法。如arguments.length 方法返回函数被调用时收到的参数数目,toString() 方法以字符串返回函数。
对象方法:定义为对象属性的函数。
对象构造函数(对象构造器):为创建新对象而设计的函数。
二、JavaScript 函数参数
函数不会对参数值进行任何检查。
1、函数参数
functionName ( parameter1,parameter2,parameter3 ) { 要执行的代码 }
parameter:在函数定义中列出的名称——形式参数。
argument:传递到函数或由函数接收的真实值——真实参数。
当调用参数时参数省略或少于被声明的数量,缺失的值被设置为:undefined。
2、参数规则
函数定义不会规定parameter的数据类型。
函数不会对传递参数argument进行类型检查,不会对接收参数argument进行数量检测。
3、arguments 对象——JavaScript内置对象
当函数调用参数过多(超过声明),使用arguments对象达到参数。
arguments 对象包含函数调用时使用的参数数组。
4、参数通过值传递
函数接受值而非参数的位置。
函数改变了参数的值但不会改变参数的原始值。
参数的改变在函数之外是不可见的。
5、对象是由引用传递的
函数改变了对象属性也会改变原始值。
对象属性的改变在函数之外是可见的。
三、JavaScript 函数调用
调用函数有三种方法,应用于不同的场景。对应声明函数的三种方法:表达式、对象方法和函数构造器。
1、以函数形式调用函数
function myFunction(a, b) { return a * b;} myFunction(1, 2);//该函数不属于任何对象,属于全局对象
全局对象
在 HTML 中是 HTML 页面本身。在浏览器中,这个页面对象就是浏览器窗口,函数自动成为一个窗口函数。
此时this关键词指代的是该全局对象。
不推荐:因为全局变量、方法或函数容易在全局对象中产生命名冲突和漏洞。
2、作为方法调用函数
fullName: function () { return this.firstName + " " + this.lastName; } myobject.fullName();
方法:被定义为对象属性的函数。
this指代的是拥有这个方法(函数代码)的对象。
以对象方法来调用函数,会导致 this 的值成为对象本身。
3.通过函数构造器调用函数
// 这是函数构造器:function myFunction(arg1, arg2) { this.firstName = arg1; this.lastName = arg2; }
// 创建了一个新对象:var x = new myFunction("Bill", "Gates"); x.firstName;
通过构造器调用函数时,会创建新对象,新对象从其构造器继承属性和方法。
构造器内的 this 关键词没有值,this值会指代调用函数时创建的新对象。
四、JavaScript 函数 Call和 Apply
作用均为:方法重用。
1、call()方法
作用:编写能够在不同对象上使用的方法。
call() 方法是JavaScript的预定义方法,以对象为参数,将方法应用于该对象的参数的函数。
2、Apply()方法
作用:编写用于不同对象的方法。
apply() 方法是JavaScript的预定义方法,以方法拥有者(对象)为参数,用来调用该对象的方法的函数。
3、call() 和 apply() 的区别
call() 方法分别接受参数。
apply() 方法接受数组形式的参数。
4、在数组上模拟 max 方法
JavaScript 数组没有 max() 方法,可以应用 Math.max() 方法。
Math.max.apply(null, [1,2,3]); // 也会返回 3
Math.max.apply(Math, [1,2,3]); // 也会返回 3
Math.max.apply(" ", [1,2,3]); // 也会返回 3
Math.max.apply(0, [1,2,3]); // 也会返回 3
5、严格模式
严格模式下,如果 apply() 方法的第一个参数不是对象,则它将成为被调用函数的所有者(对象)。在“非严格”模式下,它成为全局对象。
五、闭包 (Closure)
JavaScript 变量属于本地(局部变量)或全局(全局变量)作用域。全局变量能够通过闭包实现局部(私有)。
1、变量作用域
局部变量:函数内部定义声明的变量。在函数调用时创建,在函数完成后被删除。
全局变量:不通过关键词 var 创建的变量总是全局的,即使它们在函数中创建。活得和应用程序(窗口、网页)一样久。
函数内部可直接读取函数内部声明的局部变量和全局变量,在函数外部无法读取函数内的局部变量。
2、如何读取局部变量?
解决方法:嵌套函数——在函数内部再定义一个函数。
Javascript语言特有的"链式作用域"结构(chain scope):子对象会一级一级地向上寻找所有父对象的变量。因此,父对象的所有变量,对子对象都是可见的,反之则不成立。
3、闭包的概念
闭包就是能够读取其他函数内部变量的函数,即定义在一个函数内部的函数。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。父级函数被这个匿名函数(子函数)的作用域保护,且仅能由该子函数修改。父函数实现拥有“私有”变量。
作用:读取函数内部的变量;让这些变量的值始终保持在内存中。
4、使用闭包的注意点
①闭包内存消耗大,滥用闭包会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
②闭包会在父函数外部改变父函数内部变量的值。因此,如果把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),一定不要随便改变父函数内部变量的值。