JavaScript快速入门笔记(6):函数
本系列随笔是本人的学习笔记,初学阶段难免会有理解不当之处,错误之处恳请指正。转载请注明出处:https://www.cnblogs.com/itwhite/p/12218038.html。
函数定义
示例:
function foo(a, b, c) { // 注意: 参数名不需要 var、let、const 等关键字 return a + b * c; }
我们也可以像C/C++等语言一样,为函数参数指定默认参数值(调用时,若省略未指定默认参数的参数,则其默认为 undefined),例如:
function foo(a, b, c = false) { return [String(a), String(b), String(c)].toString(); } console.log(foo('abc', 123, true)); // abc,123,true console.log(foo('abc', 123)); // abc,123,false console.log(foo('abc')); // abc,undefined,false,JavaScript 中即使没有指定默认参数的参数,调用时也可以省略,其默认值为 undefined
不定参数
JavaScript 还支持不定参数,在函数中我们可以通过“参数对象” arguments 这个标识符来访问不定参数(参数对象类似与数组,可以通过下标访问参数,同时它还包含 length、callee、caller 等属性),例如:
function foo() { for (var i = 0; i < arguments.length; i++) { console.log(arguments[i]); } } foo(1, 2, 3);
参数对象 arguments 中的 callee 对于匿名函数的递归调用相当有用,例如:
var foo = function(n) { console.log(n); if (n > 0) { arguments.callee(n - 1); } }; foo(5); // 输出 5 4 3 2 1 0
另外,ES6 还引入了 rest 参数(以“...变量名”的形式书写),用于获取函数的多余参数(以数组形式存放),这样就可以不使用 arguments 对象了,例如:
function foo(a, b, ...others) { console.log(arguments.constructor); // 1 console.log(a); // 1 console.log(b); // 2 console.log(others); // [3, 4, 5] } foo(1, 2, 3, 4, 5);
箭头函数
JavaScript 中还支持一种简化版的函数定义方式,例如:
const foo = (x, y) => { return x * y }; // 这里也可用 var ,但 const 更安全(C/C++里挺烦const的,呵呵~~) console.log(foo(2, 3)); // 6 const bar = (x, y) => x * y; // 可以省略{} 和 return 关键字 console.log(bar(2, 3)); // 6
箭头函数中不能使用 this ,因此最好不要作为成员函数的定义方式。
函数对象的属性
函数本身也是一个对象,它本身也包含一些属性,例如:
function foo(x, y, z) { console.log(foo.name); // 输出 "foo",name 属性标识函数名 console.log(foo.length); // 输出 3,length 属性标识函数参数(形参)个数 console.log(arguments.length) // 输出 2,通过 arguments 对象属性可以获取实参个数 } foo(1, 2);
函数调用形式
JavaScript 中函数的几种调用形式如下:
- 作为函数调用:以函数的形式直接调用,例如:foo(),被调函数体中 this 指针指向全局对象;
- 作为方法调用:以对象方法的形式进行调用,例如:o.bar(),被调函数体中 this 指针指向对象 o ;
- 作为构造函数:以构造函数的形式进行调用,例如:new Quz(),被调函数函数体中 this 指向新创建的对象;
- 通过 call() 或 apply() 方法间接调用
函数调用与方法调用
JavaScript 中通常将 foo() 这种调用方式称为“函数调用”,而将 o.bar() 这种调用方式称为“方法调用”(bar() 也称作是对象 o 的方法),其区别是:
- 使用“函数调用”时,被调函数的函数体中 this 指针指向“全局对象”(通常是 window 对象)
- 使用“方法调用”时,被调函数的函数体中 this 指针指向对象 o (即调用对象)
示例(注意:即便是嵌套函数,若不使用“方法调用”的形式,也不会继承调用者的 this 值):
var x = 123; var o = { x: 456, foo: function() { console.log(this.x); // 456 var that = this; function bar() { console.log(this.x); // 123,以函数形式调用,嵌套函数不会从条用者中继承 this console.log(that.x); // 456 } bar(); // 以函数的形式调用,则输出 123 和 456 this.bar = bar; this.bar(); // 以方法的形式调用,则输出 456 和 456 } }; o.foo(); // 以方法的形式调用,将按上述注释中的描述输出
var foo = o.foo;
foo(); // 以函数的形式调用,将全部输出 123
方法链
当调用的方法返回一个对象,通过这个对象还可以条用其它方法,这种方法调用序列便形成一条“方法链”。例如:我们可以让不需要其它返回值的方法返回 this 指针,这样便可以形成“链式调用”的编程风格,示例:
var o = { foo: function() { console.log("foo() is called"); return this; }, bar: function(x,y) { console.log("bar(" + x + "," + y + ") is called"); return this; }, quz: function() { console.log("quz() is called"); return this; } }; o.foo().bar(1,2).quz();
call() 和 apply()
在 JavaScript 中任何函数都可以作为任何对象的方法(成员函数)来调用,例如:
// 示例一:普通函数作为某个对象的方法来使用 var o = { x: 123 }; function foo() { console.log(this.x); } o.foo = foo; o.foo(); // 123 // 示例二:成员函数作为别的对象的方法来使用 var c = { x: 456, bar: function() { console.log(this.x); } }; c.bar(); // 456 o.bar = c.bar o.bar(); // 123
从上面的示例中可以看到,要将某个函数作为某个对象的方法来使用,需要设置该对象的相应属性指向该函数。为了简化这个过程,JavasScript 中为每个函数(对象)都提供了 call() 和 apply()等方法,例如:
var o = { x: 123 }; function foo(a, b, c) { console.log(this.x, a, b, c); } foo.call(o, 4, 5, 6); // 输出:123 4 5 6,相当于:o.foo = foo; o.foo(1, 2, 3); delete o.foo; foo.apply(o, [4, 5, 6]); // 输出:123 4 5 6,同上
call() 与 apply() 的作用相同,区别在于接受参数的方式不同。
构造函数
请参考:“JavaScript快速入门笔记(7):对象” 中 “构造函数” 一节(https://www.cnblogs.com/itwhite/p/12230148.html)
完。