1.函数的定义
1.语法
function functionName(parameters) {
执行的代码
}
2.可以通过通过一个表达式定义,函数表达式可以存储在变量中
var x = function (a, b) {return a * b};
var z = x(4, 3); //这种函数实际上是一个匿名函数
3.函数的提升
myFunction(5); //先调用
function myFunction(y) { //后定义
return y * y;
}
4.自调用函数:如果表达式后面紧跟 () ,则会自动调用。
(function () {
var x = "Hello!!"; // 我将调用自己
})();
5.函数可作为一个值、一个表达式使用
function myFunction(a, b) {
return a * b;
}
var x = myFunction(4, 3);
var x = myFunction(4, 3) * 2;
6.函数的数据类型typeof是一个对象,有属性和方法。
2.参数
1.显式参数
函数显式参数在函数定义时列出,定义显式参数时没有指定数据类型。
2.隐式参数
函数隐式参数在函数调用时传递给函数真正的值。
我认为就是形参与实参
3.arguments 对象
- 在函数代码中,使用特殊对象
arguments[]
,开发者无需明确指出参数名,就能访问它们。 举例: 用arguments[0]可以访问第一个参数的值,相当于数组 - 引用属性
arguments.length
,可以检测函数的参数个数 - 模拟函数重载
function doAdd() { if(arguments.length == 1) { alert(arguments[0] + 5); } else if(arguments.length == 2) { alert(arguments[0] + arguments[1]); } } doAdd(10); //输出 "15" doAdd(40, 20); //输出 "60"
3.调用,关于this
JavaScript 函数有 4 种调用方式,每种方式的不同在于 this 的初始化,this指向函数执行时的当前对象。
- 作为函数调用:myFunction() 和 window.myFunction() 是一样的,this指向全局对象,web中的全局对象是浏览器窗口windows。
- 作为方法调用:this指向的对象是myObject
var myObject = { firstName:"John", lastName: "Doe", fullName: function () { return this.firstName + " " + this.lastName; } } myObject.fullName(); // 返回 "John Doe
var myObject = {
firstName:"John",
lastName: "Doe",
fullName: function () {
return this;
}
}
myObject.fullName(); // 返回 [object Object] (所有者对象)
//函数作为对象方法调用,会使得 this 的值成为对象本身
[object Object] 自定义的对象
第一个object代表用户自定义的对象的属性,
第二个Object代表用户自定义的对象的方法。
3.使用构造函数调用函数
如果函数调用前使用了 new 关键字, 则是调用了构造函数。这看起来就像创建了新的函数,但实际上 JavaScript 函数是重新创建的对象:
// 构造函数:
function myFunction(arg1, arg2) {
this.firstName = arg1;
this.lastName = arg2;
}
// This creates a new object
var x = new myFunction("John","Doe");
x.firstName; // 返回 "John"
//构造函数的调用会创建一个新的对象。新对象会继承构造函数的属性和方法。
构造函数中 this 关键字没有任何的值。this 的值在函数调用实例化对象(new object)时创建。this指向新的对象。
4.作为函数方法调用函数
JavaScript 函数是对象,有方法和属性。方法有call() 和 apply()
- apply()方法 :接收两个参数,第一个是函数运行的作用域(this),另一个是参数数组。
语法:apply([thisObj [,argArray] ]);
- call()方法 :第一个参数和apply()方法的一样,第一个时作用域this,但是传递给函数的参数必须列举出来。
语法:call([thisObject[,arg1 [,arg2 [,...,argn]]]]);
举例:
function myFunction(a, b) { return a * b; } myArray = [10, 2]; myObject = myFunction.apply(myObject, myArray); // 返回 20
5. 因为嵌套的原因,嵌套函数里的this指向windows
总结:
1、 谁调用了此函数, 那么this 就指向谁
2、如果遇到函数里面又包了一层函数,那么 this的指向就变成全局的了
3、 如果遇到new 那么指向就是 新创建的实例对象
4、如果遇到call 或apply,那么 this 指向就是 call或apply 里面的第一个参数
4.闭包
1.作用域:函数内部可以直接读取全局变量,在函数外部自然无法读取函数内的局部变量。函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上声明了一个全局变量!
2.如何从外部读取局部变量?
方法:在函数的内部,再定义一个函数。
function f1(){
var n=999;
function f2(){
alert(n); // 999
}
}
在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。
3.闭包:
既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!f1中一定要定义局部变量啊!
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
闭包就是能够读取其他函数内部变量的函数。
4.闭包的作用
一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。所以闭包很占内存!
function f1(){
var n=999; //f1要用var定义,才是局部变量!
nAdd=function(){n+=1} //注意:nAdd是一个全局变量
function f2(){
alert(n);
}
return f2;
}
var result=f1(); //result实际就是闭包f2函数
result(); // 999
nAdd(); //nAdd的值是一个匿名函数),而这个匿名函数本身也是一个闭包
result(); // 1000
第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
5.闭包与this
代码一:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());
返回值是The Window,外面的函数指向object,当函数里套一个函数,此时this发生了变化, 指向了全局 window
代码二闭包:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()());
返回值是My Object。
作为方法调用,哪个对象调用this就指向哪个对象。
这是一个闭包。