这是重读红宝书(JavaScript高级程序设计 第4版)的第7篇文章,本节我们来看看函数:函数本质、函数名、理解参数、函数内部 本节涉及源码见仓库 github.com/adamswan/Re…
1、定义函数
函数是ECMAScript中最有意思的部分之一,这主要是因为函数实际上是对象,函数名就是指向函数对象的指针,而且不一定与函数本身紧密绑定
函数声明:
函数声明形式定义的函数,存在函数声明提升现象。在执行代码时,JavaScript 引擎会先执行一遍扫描, 把发现的函数声明提升到源代码树的顶部,所以可以在声明行之前编写调用代码
function sum (num1, num2) {
return num1 + num2;
}
函数表达式/匿名函数:
表达式无函数声明提升现象
let sum = function(num1, num2) {
return num1 + num2;
};
箭头函数:
let sum = (num1, num2) => {
return num1 + num2;
};
箭头函数注意点:
1、 没有 prototype
2、 没有 arguments
3、 也没有自己的 this ,箭头函数中的 this 是所在环境的,并且在声明时就确定了指向,而非调用时
4、 用 call、apply、bind 无法修改箭头函数中的 this 指向
5、 对象上的方法,不推荐用箭头函数定义,因为 this 可能不指向该对象
4、 和普通 function 最大的区别:箭头函数只能被调用,不能作为构造函数 new 一个对象,因此说它消除了普通 function 的二异性,因为普通 function 既可以直接调用,又可以 new 对象
为何箭头函数不能用来 new 对象?TC39 这个组织将箭头函数设计得很精妙,箭头函数没有 prototype,这样就无法通过它挂载公共方法;没有自己的 this,这样就无法给对象添加属性
2、函数名
函数名本质就是一个指针。把 sum 设置为 null 之后,就切断了它与函数之间的关联。而 anotherSum()还是可以照常调用,没有问题
function sum(num1, num2) {
return num1 + num2;
}
console.log(sum(10, 10)); // 20
let anotherSum = sum;
console.log(anotherSum(10, 10)); // 20
sum = null;
console.log(anotherSum(10, 10)); // 20
所有,用 function 声明相同函数,后者会覆盖前者
function addSomeNumber(num) {
return num + 100;
}
function addSomeNumber(num) {
return num + 200;
}
let result = addSomeNumber(100); // 300
3、理解参数
ECMAScript 函数既不关心传入的参数个数,也不关心这些参数的数据类型。定义函数时要接收两个参数,并不意味着调用时就传两个参数。你可以传一 个、三个,甚至一个也不传,解释器都不会报错。
之所以会这样,主要是因为 ECMAScript 函数的参数在内部表现为一个类数组。函数被调用时总会接 收一个类数组,但函数并不关心这个类数组中包含什么。
在使用 function 关键字定义函数时,可以在函数内部访问 arguments 对象,它就是类数组,从中取得传进来的每个参数值:第一个参数是 arguments[0],第二个参数是 arguments[1],通过 arguments.length 属性可以知道传入了多少个参数
函数传值的本质,就是用将传入的值,填充 arguments 类数组的槽位
function sayHi() {
console.log("Hello " + arguments[0] + ", " + arguments[1]);
}
sayHi("高圆圆", "刘亦菲");
// Hello 高圆圆, 刘亦菲
// 当然,也可以混用:
function sayHi2(name) {
console.log(name + ", " + arguments[1]);
}
sayHi2("赵丽颖", "艾玛沃特森");
// 赵丽颖, 艾玛沃特森
4、函数内部
arguments
arguments 类数组除了能存储参数外,还有一个 callee 属性,指向类数组所在的函数
function getName() {
// callee 指向所在的函数
console.log(arguments.callee);
// f getName
}
getName();
this
this的指向、修改this指向的方法,不再次赘述
new.target
new.target 属性,用于检测是否通过 new 关键字调用的
如果函数是正常调用的,new.target 的值是 undefined;
如果是使用 new 关键字调用的,则 new.target 的值指向构造函数
function gaoyuanyuan() {
console.log("高圆圆", new.target);
// 高圆圆 undefined
}
gaoyuanyuan();
function Liuyifei() {
console.log("刘亦菲", new.target);
// 刘亦菲 ƒ Liuyifei
}
new Liuyifei();