网站
引入
函数写好之后,不会自动执行,必须通过调用才会运行。
不同的调用方式,最明显的区别是:函数什么时候执行,以及函数里的 this 指向谁。
正文
定义
定义
函数调用方式,就是让函数执行的不同写法。调用方式会影响函数的执行时机、参数传递,以及
this的指向。
函数本质上是把一段代码封装起来,需要时再调用。
function sayHello() {
console.log("你好");
}
sayHello();这里的 sayHello() 就是在调用函数。
普通函数调用
普通函数调用是最常见的写法,直接使用 函数名()。
function add(a, b) {
return a + b;
}
const result = add(1, 2);
console.log(result);a 和 b 是参数,1 和 2 是调用函数时传进去的数据。
return 后面的内容是函数执行后交回来的结果。
函数表达式调用
函数也可以保存到变量里,再通过变量名调用。
const sayName = function (name) {
console.log("我的名字是" + name);
};
sayName("Tom");这里的 sayName 保存的是一个函数。
调用时仍然使用 sayName()。
箭头函数调用
箭头函数也是函数的一种写法,调用方式和普通函数一样。
const add = (a, b) => {
return a + b;
};
console.log(add(3, 5));如果函数体只有一行返回值,也可以简写。
const add = (a, b) => a + b;
console.log(add(3, 5));初学阶段可以先用完整写法,方便看清楚 return 的作用。
对象方法调用
对象里的函数通常叫做方法。
通过 对象名.方法名() 调用。
const user = {
name: "Tom",
sayName: function () {
console.log(this.name);
}
};
user.sayName();这里的 sayName 是 user 对象的方法。
user.sayName() 表示通过 user 调用这个方法。
在这种调用方式里,this 通常表示当前调用这个函数的对象,也就是 user。
构造函数调用
构造函数通常配合 new 使用,用来创建对象。
function User(name, age) {
this.name = name;
this.age = age;
}
const user = new User("Tom", 18);
console.log(user.name);new User("Tom", 18) 会创建一个新对象。
构造函数里的 this 指向这个新创建的对象。
构造函数名字通常首字母大写,例如 User、Person。
事件回调函数调用
事件里的函数不是我们手动立刻调用,而是浏览器在事件发生时调用。
<button id="btn">点击</button>const btn = document.querySelector("#btn");
btn.addEventListener("click", function () {
console.log("按钮被点击了");
});这里没有写成 function () {}(),而是把函数交给 addEventListener()。
当用户点击按钮时,浏览器会自动执行这个函数。
定时器回调函数调用
定时器里的函数也是回调函数,由浏览器在指定时间后调用。
setTimeout(function () {
console.log("1 秒后执行");
}, 1000);1000 表示 1000 毫秒,也就是 1 秒。
这段代码不是立刻输出,而是等待时间到了再执行函数里的代码。
立即执行函数
立即执行函数是定义后马上调用的函数。
(function () {
console.log("马上执行");
})();这种写法以前常用来创建一个独立作用域,避免变量污染外部。
现在学习阶段不需要经常使用,先看懂即可。
使用 call() 调用
call() 可以手动调用函数,并指定函数里的 this。
function sayName() {
console.log(this.name);
}
const user = {
name: "Tom"
};
sayName.call(user);这里 sayName.call(user) 表示调用 sayName(),并让函数里的 this 指向 user。
使用 apply() 调用
apply() 和 call() 类似,也可以指定 this。
区别是:apply() 传参数时使用数组。
function add(a, b) {
return a + b;
}
const result = add.apply(null, [1, 2]);
console.log(result);这里不需要使用 this,所以第一个参数写 null。
使用 bind() 生成新函数
bind() 不会立刻调用函数,而是返回一个绑定好 this 的新函数。
function sayName() {
console.log(this.name);
}
const user = {
name: "Tom"
};
const fn = sayName.bind(user);
fn();bind() 更像是先准备好一个函数,后面需要时再调用。
常见写法
| 写法 | 作用 |
|---|---|
sayHello(); | 普通函数调用 |
add(1, 2); | 调用函数并传入参数 |
user.sayName(); | 调用对象的方法 |
new User("Tom"); | 使用构造函数创建对象 |
btn.addEventListener("click", fn); | 把函数作为事件回调交给浏览器 |
setTimeout(fn, 1000); | 把函数作为定时器回调交给浏览器 |
sayName.call(user); | 调用函数并指定 this |
sayName.apply(user, args); | 调用函数并指定 this,参数用数组传 |
sayName.bind(user); | 返回一个绑定好 this 的新函数 |
例子
普通调用和返回值
函数执行后,可以通过 return 把结果交回来。
function getTotal(price, count) {
return price * count;
}
const total = getTotal(10, 3);
console.log(total);方法调用和 this
对象调用方法时,this 通常指向这个对象。
const student = {
name: "Jack",
showName: function () {
console.log(this.name);
}
};
student.showName();事件中调用函数
点击按钮时,再执行 showMessage()。
<button id="btn">显示消息</button>const btn = document.querySelector("#btn");
function showMessage() {
console.log("欢迎学习 JS");
}
btn.addEventListener("click", showMessage);注意这里写的是 showMessage,不是 showMessage()。
如果写成 showMessage(),函数会在绑定事件时就立刻执行。
特点
- 函数必须调用后才会执行
函数名()表示立刻调用函数- 函数可以接收参数,也可以通过
return返回结果 - 对象方法调用时,
this通常指向调用这个方法的对象 new调用构造函数时,this指向新创建的对象- 事件回调和定时器回调不是立刻执行,而是交给浏览器在合适的时候执行
call()和apply()会立刻调用函数bind()不会立刻调用函数,而是返回一个新函数
注意事项
- 函数名后面加
(),表示现在就执行 - 把函数作为参数传递时,很多时候不要加
() return后面的代码不会继续执行- 函数可以没有参数,也可以没有返回值
this的值和函数在哪里定义关系不大,更重要的是函数怎么被调用- 箭头函数没有自己的
this,初学阶段不要随便用箭头函数写对象方法
const user = {
name: "Tom",
sayName: () => {
console.log(this.name);
}
};
user.sayName();上面这种写法容易出问题,因为箭头函数里的 this 不是 user。
对象方法初学阶段建议先使用普通函数写法。
const user = {
name: "Tom",
sayName: function () {
console.log(this.name);
}
};理解
函数调用方式可以理解为:用不同方式让同一段代码执行。
普通函数调用关注的是执行代码和拿到结果。
对象方法调用还要关注是谁在调用它,因为这会影响 this。
事件和定时器里的函数不是自己马上执行,而是先交给浏览器,等用户操作或时间到了再执行。
call()、apply()、bind() 主要用于控制 this,初学时先知道它们的区别即可。
引出
理解函数调用方式之后,可以继续学习 JS this,重点理解不同调用方式下 this 的变化。
也可以结合 JS 事件 和 JS DOM API,理解页面交互中函数是怎么被浏览器调用的。