函数概述
JavaScript中的函数是一组操作的集合体,函数中封装了一组语句。
并且函数是可以执行的,而其他类型的数据是不能执行的。
使用函数的好处
- 提高代码的复用性
- 提高代码的可读性
定义函数
JavaScript中定义函数有两种方式:
- 函数声明
- 表达式
定义的基本语法如下:
// 函数声明方式定义函数
function 函数名([参数列表]) {
// 函数体
}
// 表达式方式定义函数
var 函数名 = function ([参数列表]) {
// 函数体
};
例如:
// 函数声明方式定义函数
function f1(msg) {
console.log(msg);
}
f1('hello f1()...');
// 表达式方式定义函数
var f2 = function (msg) {
console.log(msg);
};
f2('hello f2()...');
调用函数
JavaScript中调用函数有如下几种方式:
函数名()
:通过函数名直接调用。对象名.函数名()
:通过对象调用。new 函数名()
:通过new
调用。函数名.call(对象名)
或函数名.apply(对象名)
:临时让某方法成为对象的属性进行调用。
函数名()
// 通过函数名直接调用
function hello(msg) {
console.log(msg);
}
hello('hello world');
对象名.函数名()
在 JavaScript 中,您可以把函数定义为对象方法。
// 通过对象调用
var obj = {
name: '张三',
print: function () {
console.log(this.name);
}
};
obj.print();
new 函数名()
如果函数调用的前面是new
关键字,那么这是一个构造函数调用。
它看起来像你创建一个新的函数,但由于 JavaScript 函数是对象,你实际上创建一个新对象:
// 通过new调用
function hello(name, age) {// 这是函数构造器
this.name = name;
this.age = age;
}
// 创建了一个新对象
var h = new hello('tom', 18);
console.log(h.name, h.age);// 可以通过对象访问属性的方式访问函数内的定义的属性
构造器调用会创建新对象。新对象会从其构造器继承属性和方法。
构造器内的 this
关键词没有值。
this
的值会成为调用函数时创建的新对象。
函数名.call(对象名)
或函数名.apply(对象名)
还可以通过call()
或apply()
方法让需要被调用的函数临时绑定到某个对象来完成调用。
// 临时让某方法成为对象的属性进行调用。
// 1.创建一个对象
var obj = {};
// 2.创建一个方法
var f1 = function () {
console.log('f1...');
};
// 3.临时让某方法成为对象的属性进行调用
f1.apply(obj);// 或f1.call(obj)
回调函数
概念
JavaScript中的回调函数就是将函数A作为参数传递到函数B中,并且在函数B中进行调用,那么函数A就被称为回调函数。如果没有名称(函数表达式),就叫做匿名回调函数。
// 1.创建普通函数A
function A() {
console.log('function A()...');
}
// 2.创建普通函数B,但是传递一个函数fun作为形参,并且在函数B内部调用函数fun
function B(fun) {
fun();
}
// 3.将函数A作为实参,传递给函数B
B(A);
回调函数在异步场景中使用较多,如Ajax请求、setTimeout等。
回调函数传参
回调函数如果想要传参有如下两种解决方式:
- 将回调函数的参数作为与回调函数同级的参数进行传递
// 1.创建普通函数A
function A(msg) {// 这里A将作为回调函数,需要传递一个msg参数
console.log(msg);
}
// 2.创建普通函数B,但是传递一个函数fun作为形参,并且在函数B内部调用函数fun
function B(fun, msg) {// 这里fun作为回调函数、msg作为回调函数的参数,都作为函数B的参数进行传递
fun(msg);// 在函数体内将msg传递给回调函数fun作为参数
}
// 3.将函数A作为实参,传递给函数B
B(A, "hello world");// 传递了两个实参:回调函数和回调函数需要的参数
// 这种匿名方式看起来更好点,可以得知给函数B传递的第一个参数是一个函数,就是回调函数;第二个参数是回调函数需要的参数。
B(function (msg) {
console.log(msg)
}, 'hello world');
- 回调函数的参数在函数内部创建
// 1.创建普通函数A
function A(msg) {// 这里A将作为回调函数,需要传递一个msg参数
console.log(msg);
}
// 2.创建普通函数B,但是传递一个函数fun作为形参,并且在函数B内部调用函数fun
function B(fun) {
// 在函数B内部定义一个值作为参数传递给回调函数fun
var msg = 'hello world';
fun(msg);
}
// 3.将函数A作为实参,传递给函数B
B(A);// 传递了一个实参:回调函数
// 使用匿名的方式传递回调函数
B(function (msg) {
console.log(msg);
});
注意:前者从外向内传递数据;后者从内向外传递数据(即在回调函数中接收数据),node.js的fs
模块的很多方法都是这样操作文件的。
IIFE
概念
IIFE全称是Immediately-Invoked Function Expression,叫做立即执行函数,所谓的立即执行函数就是在定义函数中立刻调用该函数。
我们知道在函数名后面跟一对小括号()
表示函数调用,那么如下写法就应该可以调用函数:
function hello() {
}();
但事实上却会报错:SyntaxError: Unexpected token ')'
。所以解决方法是让function
不出现在行首,让引擎将其理解成一个表达式,常用的两种方法是:
(function() { /* code */ }());
(function() { /* code */ })();
例如:
// 不传递参数
(function () {
console.log('hello world');
})();
// 传递参数
(function (msg) {
console.log(msg);
})('hello world');
作用
立即执行函数作用如下:
- 隐藏实现
- 不会污染全局命名空间避免同名冲突
- 用它来编码js模块
// 函数内定义的变量仅作用在函数内部,不会与全局变量产生同名冲突
(function () { // 立即执行函数
var a = 3;
console.log(a + 3)
})();
var a = 4;
console.log(a);
// 隐藏实现,向外暴露函数
(function () {
var a = 1;
function test() {
console.log(++a)
}
$ = function () { // 向外暴露一个全局函数
return {
test: test
}
}
})();
$().test(); // 1. $是一个函数 2. $执行后返回的是一个对象
函数中的this
概述
在HTML中任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是Window
,所有函数内部都有一个变量this
,它的值是调用函数的当前对象。如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<script type="text/javascript">
console.log(this);
</script>
</body>
</html>
this
的值
在函数中,this
的值分为如下几种情况:
fun()
:该函数fun
内this的值为Window
对象。obj.fun()
:该函数fun
内this的值为调用该函数的对象obj
。var o = new obj()
:则this的值为新创建的对象o
。fun.call(obj)
:则this的值为传入的对象obj
。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<script type="text/javascript">
console.log(this);// this是谁?Window对象
function fun() {
console.log(this);// this是谁?Window对象
}
fun();
function Person(name, age) {
console.log(this);
this.name = name;
this.age = age;
this.say = function () {
console.log(this);
console.log('我是', name, ',今年' + age + '岁。');
}
}
Person('李四', 20);// this是谁?Window对象
var p = new Person('张三', 18);// this是谁?p对象
p.say();// this是谁?p对象
var obj = {};
p.say.call(obj);// this是谁?obj对象
var say=p.say;
say();// this是谁?Window对象
function f1() {
function f2() {
console.log(this);
}
f2();// this是谁?Window对象
}
f1();
</script>
</body>
</html>
参考资料:
- js 彻底理解回调函数
- JavaScript的IIFE(即时执行方法)