1、 函数是什么?
由 function关键字
、函数名称和一些语句组成的函数体称{}
之为函数。在 JavaScript中,函数与其他对象一样具有属性和方法,区别是函数可以被调用。如果一个函数中没有使用return语句,则它默认返回 undefined
。
2、函数定义方式
(1) 函数声明
函数声明是定义一个具有指定参数的函数。
-
语法:
function 函数名([param[, param[, ... param]]]) { statements }
-
可以在函数声明之前调用函数,不会有语法问题–因为会进行预解析找到函数定义
// 可以在函数声明之前调用函数,不会有语法问题--因为会进行预解析找到函数定义
hoisted(); // "foo"
function hoisted() {
console.log("foo");
}
(2) 函数表达式
- 语法:
// 语法
var myFunction = function name([param[, param[, ... param]]]) { statements }
// 匿名写法
var myFunction = function() {
// statements
}
// 命名写法
var myFunction = function namedFunction(){
// statements
}
- 案例:
// 定义一个函数表达式
var foo = function() {}
// 访问foo 变量name属性
foo.name // "foo"
var foo2 = foo
foo2.name // "foo"
var bar = function baz() {}
bar.name // "baz"
console.log(foo === foo2); //true
console.log(typeof baz);// undefined--因为这里是函数表达式,如果把baz函数单独拿出来声明就不是undefined
console.log(bar === baz); // false (errors because baz == undefined)
// 在函数表达式之前调用函数,会有语法错误。
notHoisted(); // TypeError: notHoisted is not a function
var notHoisted = function() {
console.log("bar");
};
把baz函数单独拿出来声明就不是undefined
// 把baz函数单独拿出来声明就不是undefined
function baz() {}
console.log(typeof baz) // function
(3)动态创建函数
- 方法一:使用函数表达式创建
var myFunc;
if (num == 0){
myFunc = function(theObject) {
theObject.make = "Toyota"
}
}
- 方法二:使用 Function 对象创建
var x = 10;
function createFunction1() {
var x = 20;
return new Function('return x;'); // 这里的 x 指向最上面全局作用域内的 x
}
(4) 箭头函数 (=>)
A、声明是箭头函数
- JavaScript 箭头函数大致相当于 python 中的 lambda 函数;
- 这些是匿名函数,它们有自己的特殊语法,接受一定数量的参数,并在其封闭的作用域的上下文(即定义它们的函数或其他代码)中操作。
B、箭头函数定义
- 语法一:括号内的是参数列表,后跟“胖箭头”(=>),最后是函数体。
- 这与传统函数非常相似,我们只是省略 function 关键字并在参数后添加一个胖箭头(=>)。
([param] [, param]) => { statements }
- 语法二:如果函数体是单个表达式,则可以不使用花括号并将其置于内联中(省略大括号直接将表达式写在一行中)。 表达式的结果将由函数返回。
- 如果只有一个参数,你甚至可以省略参数的括号。
// 多个参数
const add = (a, b) => a + b;
// 只有一个参数
const getFirst = array => array[0];
- 语法三:高级语法,如果想要一个对象的单个表达式,请用花括号包裹该对象,返回的就是一个对象;
(name, description) => ({name: name, description: description});
C、箭头函数的特点
(5) 生成器函数
用 function *
定义一个函数并返回一个 Generator 对象称之为 生成器函数。配合上 yield 关键字可以变成 异步函数。
(6)异步函数 AsyncFunction
可以使用 AsyncFunction 对象,动态创建异步函数。AsyncFunction 并不是一个全局对象,需要通过Object.getPrototypeOf(async function(){}).constructor
来生成。JavaScript 中每个异步函数都是 AsyncFunction 的对象。
// 使用实例
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
var AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
var a = new AsyncFunction('a',
'b',
'return await resolveAfter2Seconds(a) + await resolveAfter2Seconds(b);');
a(10, 20).then(v => {
console.log(v); // 4 秒后打印 30
});
3、函数参数
(1)默认参数
// 1、参数默认值为 undefined
function multiply(a, b) {
b = (typeof b !== 'undefined') ? b : 1;
return a*b;
}
multiply(5); // 5
// 2、使用默认参数重新上面函数
function multiply(a, b = 1) {
return a*b;
}
multiply(5); // 5
(2)剩余参数
用 ...
来表示不确定数量的剩余参数,
// 1、语法
function(a, b, ...theArgs) {
// ...
}
// 2、实例
function multiply(multiplier, ...theArgs) {
return theArgs.map(x => multiplier * x);
}
var arr = multiply(2, 1, 2, 3);// 把multiplier=2,theArgs=1,2,3传入函数multiply
console.log(arr); // [2, 4, 6]
arguments实参对象
arguments 是一个数组对象,包含函数的实际参数。
function myConcat(separator) {
var result = '';
var i;
for (i = 1; i < arguments.length; i++) {
result += arguments[i] + separator;
}
return result;
}
myConcat(", ", "red", "orange", "blue");
// 结果: red, orange, blue,
4、方法
当函数是一个对象的属性时,称之为方法。
(1)方法定义
从ECMAScript 2015开始,采用了更简短的方式来定义方法。
var obj = {
foo: function() {
/* code */
}
};
// 用下面简写的方式代替上面
var obj = {
foo() {
/* code */
}
};
(2) 生成器方法
// 用有属性名的语法定义方法(ES6之前):
var obj2 = {
g: function*() {
var index = 0;
while(true)
yield index++;
}
};
// 同一个方法,简写语法:
var obj2 = {
* g() {
var index = 0;
while(true)
yield index++;
}
};
var it = obj2.g();
console.log(it.next().value); // 0
console.log(it.next().value); // 1
(3) Async 方法
// 用有属性名的语法定义方法(ES6之前):
var obj3 = {
f: async function () {
await some_promise;
}
};
// 同一个方法,简写语法:
var obj3 = {
async f() {
await some_promise;
}
};
(4) Async 生成器方法
var obj4 = {
f: async function* () {
yield 1;
yield 2;
yield 3;
}
};
// 同一个方法,简写语法:
var obj4 = {
async* f() {
yield 1;
yield 2;
yield 3;
}
};
(5) get 和 set
使用 get 和 set 关键字将属性与函数关联起来,可以对属性做一些复杂的自定义操作。
5、其他特性
(1) 检测函数是否存在
typeof 操作符可以判断一个函数是否存在。
if ('function' === typeof window.noFunc) {
// use noFunc()
} else {
// do something else
}
(2) 闭包
闭包(closure)就是通过嵌套函数的方式,缓存嵌套函数及其执行环境,等待下一次调用。当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了。
(3) 预定义函数
JavaScript语言有一些全局函数可用:eval()、isNaN()、parseInt()等。
(4) Function 对象
Function 对象 可以动态创建 函数,实际上每个函数都是一个 Function 对象。