一.函数描述
-
Function对象 在JavaScript中,每个函数其实都是一个Function对象,因为它们可以像任何其他对象一样具有属性和方法。它们与其他对象的区别在于函数可以被调用。
-
return语句 如果一个函数中没有使用return语句,则它默认返回undefined。要想返回一个特定的值,则函数必须使用 return 语句来指定一个要返回的值。(使用new关键字调用一个构造函数除外)。return的作用和break类似。
-
实参与形参调用函数时,传递给函数的值被称为函数的实参(值传递),对应位置的函数参数名叫作形参。
function func(形参1,形参2){
//函数执行代码
}
func(实参1,实参2);//调用时传参
- this指向在函数执行时,this 关键字并不会指向正在运行的函数本身,而是
指向调用该函数的对象。所以,如果你想在函数内部获取函数自身的引用,只能使用函数名或者使用arguments.callee属性(严格模式下不可用),如果该函数是一个匿名函数,则你只能使用后者。
二.函数定义
2.1 函数声明与函数表达式
函数声明会在任何代码执行之前先被读取并添加到执行上下文中,这个过程叫函数声明提升。
function functionName(){
//要执行的代码
}
函数表达式必须等到代码执行到这一行,才会在执行上下文中生成函数定义。函数表达式不会提升,所以不能在定义之前调用。
var myFunction = function name(a, b) {
return a + b;
};
console.log(myFunction("蔡", "徐坤"));
2.2 匿名函数
匿名函数就是没有名称的函数,匿名函数定义了必须要使用。
function() {
console.log("hello world");
}
- 匿名函数的应用场景
1 作为其他函数的参数
function test(fn) {
fn();
}
test(function () {
console.log("hello world");
});
2 作为其他函数的返回值
function test() {
return function () {
console.log("hello world");
};
}
let fn = test();
fn();
3作为一个立即执行的函数
(function () {
console.log("hello world");
})()
2.3 箭头函数(ES6 中)
let 函数名称 = (形参列表) =>{
需要封装的代码;
}
关于省略
/*4.1 在箭头函数中如果只有一个形参, 那么()可以省略*/
let say = name => {
console.log("hello " + name);
}
/*4.2在箭头函数中如果{}中只有一句代码, 那么{}也可以省略*/
let say = name => console.log("hello " + name);
say("world");
//这句话等价于{return console.log("hello " + name)}
let say = name => {console.log("hello " + name);}
say("world");
//这句话没有return返回值
- 箭头函数特点:
1.箭头函数没有 this,所以需要通过查找作用域链来确定 this 的值。这就意味着如果箭头函数被非箭头函数包含,this 绑定的就是最近一层非箭头函数的 this。
2.箭头函数没有自己的 arguments 对象,这不一定是件坏事,因为箭头函数可以访问外围函数的 arguments 对象
3.不能通过 new 关键字调用,也没有 new.target 值。
4.由于不能使用 new 调用箭头函数,所以也没有构建原型的需求,于是箭头函数也不存在 prototype 这个属性。
5.没有 super,箭头函数没有原型,故也不能通过 super 来访问原型的属性,所以箭头函数也是没有 super 的。同this、arguments、new.target 一样,这些值由外围最近一层非箭头函数决定。 >箭头函数不被使用的场景: 不应被用在定义对象的方法上
具有动态上下文的回调函数,也不应使用箭头函数
不能应用在构造函数中
避免在 prototype 上使用
避免在需要 arguments 上使用
2.4 回调函数与递归函数
回调函数是一个作为参数传给另一个 JavaScript 函数的函数。这个回调函数会在传给的函数内部执行。 为啥要回调?
- 客户端 JavaScript 在浏览器中运行,并且浏览器的主进程是单线程事件循环。如果我们尝试在单线程事件循环中执行长时间运行的操作,则会阻止该过程。从技术上讲这是不好的,因为过程在等待操作完成时会停止处理其他事件。
- 例如,alert 语句被视为浏览器中 javascript 中的阻止代码之一。如果运行 alert,则在关闭 alert 对话框窗口之前,你将无法在浏览器中进行任何交互。为了防止阻塞长时间运行的操作,我们使用了回调。
递归函数
递归函数就是在函数中自己调用自己, 我们就称之为递归函数
递归函数在一定程度上可以实现循环的功能
每次调用递归函数都会开辟一块新的存储空间, 所以性能不是很好
function login() {
// 1.接收用户输入的密码
let pwd = prompt("请输入密码");
// 2.判断密码是否正确
if(pwd !== "123456"){
login();
}
// 3.输出欢迎回来
alert("欢迎回来");
}
login();
三.函数内部
3.1 函数的arguments对象和参数
3.1.1 函数的arguments对象
arguments,代表所有实参的集合。通过下标获取参数的每一位;通过length获取实参的个数;
集合是类数组,可以使用下标,但是没有数组中的各种方法。
//arguments 代表所有实参的集合(类数组),可以通过下标获取各个实参,通过length获取集合长度
function args() {
console.log(arguments);
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
args(23, 45, 999, 10.9, "蔡徐坤", "后面还有");
3.1.2 函数的参数(ES6)
- 除了普通参数外,Es6新增了两个新的参数:默认参数和剩余参数。 默认参数
1.在 ES6 之前可以通过
逻辑运算符来给形参指定默认值
格式: 条件 A || 条件 B
如果条件 A 成立, 那么就返回条件 A
如果条件 A 不成立, 无论条件 B 是否成立, 都会返回条件 B
function getSum(a, b) {
a = a || "你好";
b = b || "JavaScript";
console.log(a, b);
}
getSum(); //你好 JavaScript
getSum("hello", "world");//hello world
2.从 ES6 开始, 可以直接在形参后面通过=指定默认值
function getSum(a = "你好", b = "前端") {
console.log(a, b);
}
getSum(); //你好 前端
getSum("hello", "world"); //hello world
注意点: ES6开始的默认值还可以从其它的函数中获取
function getSum(a = "音乐天才", b = getDefault()) {
console.log(a, b);
}
getSum();//音乐天才 蔡徐坤
function getDefault() {
return "蔡徐坤";
}
剩余参数
剩余参数语法允许将不确定数量的参数表示为数组。
function name(a, b, c, ...arr) {
console.log(a, b, c, arr); //1 2 3 [4, 5,6,7,78]
}
name(1, 2, 3, 4, 5, 6, 7, 78);
3.2 函数的this(详情见后面this指向的总结)
this取值是在函数执行是确定的
普通函数 ://window
普通函数的call方法fn.call({name:1})://{name:1}
普通函数的bind方法fn.bind({name:1})://{name:1}
const fn2= fn1.bind({name:1})
fn2()//bind会返回一个新的函数执行
对象的方法执行,this指向该对象 obj.say()
setTimeout(function(){console.log(this)},2000)function里面的this指向window
setTimeout(()=>{},2000)指向外面的对象
class中的指向实例本身