「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。
函数对任何语言来说都是一个核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方、 任何时候调用执行。
如何定义一个函数?
1. 函数声明式
function eat (food) {
console.log("今天想吃:"+food)
}
2. 函数表达式
// 定义一个变量eat,并初始化为一个函数;
let eat = function(food) {
console.log("今天想吃:"+food)
};
3. 箭头函数
// 与使用函数表达式定义一个函数对象很相似,在写法更简洁
let eat = (food) => {
console.log("今天想吃:"+food)
}
4. 使用Function 构造函数
// Function 构造函数接收任意多个字符串参数,最后一个参数为函数体
let eat = new Function("food1","food2", "return console.log('今天想吃' + food1 + '和' + food2)")
eat('迷糊桃','烤地瓜'); //今天想吃迷糊桃和烤地瓜
// 不推荐,影响性能
// 因为这段代码会被解释两次:第一次是将它当作常规 ECMAScript 代码,第二次是解释传给构造函数的字符串。
小结
函数实际上是对象,每个函数都是 Function 类型的实例,而 Function 也有属性和方法,跟其他引用类型一样。
因为函数是对象,所以函数名就是 指向函数对象的指针,而且不一定与函数本身紧密绑定。
函数声明与函数表达式的区别
解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问); 至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。
先来看两段代码:
console.log(calcu(66, 88)); //154
function calcu(num1, num2){
return num1 + num2;
}
console.log(calcu2(66, 88)); //Uncaught TypeError: calcu2 is not a function
var calcu2 = function (num1, num2){
return num1 + num2;
}
上面两段代码都是在定义函数之前调用它。使用函数声明方式创建的函数在他之前可以正常运行,而使用函数表达式却报错了。
这里设计到一个函数声明提升的概念,因为js引擎在加载数据时,他优先读取函数声明(找function),然后将他添加到执行上下文,所以函数如果在调用之后定义,会被提升到顶部。
但是函数表达式,看做初始化一个变量,只不过这个变量存储的是函数。在其之前调用的话,执行上下文中没有这函数,代码就会出错。
关于函数表达式
任何时候, 只要函数被当作值来使用,它就是一个函数表达式。但这并不是使用函数表达式的唯一 方式。
函数表达式看起来像是变量赋值的语句,创建的函数然后赋值给一个变量,这种方式创建的函数叫匿名函数,可以看到在function关键字后面函数名字
var calcu2 = function (num1, num2){
return num1 + num2;
}
console.dir(calcu2)
// 打印一个未赋值的匿名函数看看
console.dir(function(a){return a})
ps: 看上面👆🏻
- 赋值给一个变量的匿名函数,函数名(name属性)就是这个被赋值的变量名
- 未赋值的匿名函数,它的name是空字符串
关于函数名
函数实际就是对象,函数名就是指向函数的指针;同其他包含对象指针的变量一样。 所以说,一个函数可以有多个名称;
function sum(num1, num2){
return num1 + num2;
}
console.log(sum(2,4)); // 6, 函数名加括号 => 执行函数;
let name1 = sum; // 函数名是指向函数的指针
console.log(name1(3,3)) // 6, 这时sum与name1 都指向同一个函数
sum = null; // 断开sum与函数间的关联
console.log(name1(3,3)); // 6, 不会影响name1
ECMAScript 6 的所有函数对象都会暴露一个只读的 name 属性,其中包含关于函数的信息。多数情 况下,这个属性中保存的就是一个函数标识符,或者说是一个字符串化的变量名。即使函数没有名称, 也会如实显示成空字符串。如果它是使用 Function 构造函数创建的,则会标识成"anonymous"
一起来看下不同方式创建的函数,他们的函数名都是什么样的:
function fn1(){};
let fn2 = function(){};
let fn3 = ()=> {};
let fn4 = new Function();
console.log(fn1.name); // fn1
console.log(fn2.name); // fn2
console.log(fn3.name); // fn3
console.log(fn4.name); // anonymous
// 未赋值的匿名函数
console.log((function(){}).name); // ''
// 获取函数,设置函数
let people = {
years: 18,
get age() {
return this.years;
},
set age(newAge) {
this.years = newAge;
}
}
// Object.getOwnPropertyDescriptor()方法可以取得指定属性的属性描述符。
let propertyDescriptor = Object.getOwnPropertyDescriptor(people, 'age');
console.log(propertyDescriptor.get.name); // get age
console.log(propertyDescriptor.set.name); // set age
// 使用 bind()实例化
function fn1(){};
console.log(fn1.bind(null).name); //bound fn1