目录
一、函数的声明
1.1、自定义函数
语法格式:
function 函数名称(参数列表) {
函数体
[return 值]
}
注意:
(1)function 是声明函数的关键字必须小写;
(2)function 关键字后必须跟函数名,函数名一般使用动词,需要符合命名规则;
(3)函数名后跟一对小括号,小括号后跟一对大括号,大括号内是函数体。
1.2、函数表达式(匿名函数)
语法格式:
var 函数引用名称 = function(参数列表) {
函数体
[return 值]
}
注意:
(1)函数表达式方式声明函数仍然需要使用 function 关键字;
(2)function关键字后紧跟一对小括号,小括号后跟一对大括号,大括号内是函数体;
(3)由于这种定义的函数没有名字,因此需要把函数赋值给一个变量 。
二、函数的调用
2.1、自定义函数调用
使用函数名称来调用
// 声明函数
function myFunction() {
}
// 调用函数
myFunction();
2.2、函数表达式调用
需要通过函数变量名来调用
// 声明函数
var myFunction = function() {
}
// 调用函数
myFunction();
2.3、自定义函数调用与函数表达式调用区别
<script>
fn1();
function fn1() {
console.log('fn1');
}
fn2();//报错
var fn2 = function() {
console.log('fn2');
};
</script>
区别:
(1)如果是自定义函数来声明的函数,在声明函数语句的前后都可以调用;如果是函数表达式来声明的函数,只能在声明语句之后调用,不能在声明语句之前调用。
(2)对于自定义函数方式来声明的函数,使用函数名称来调用;而对于函数表达式方式声明的函数,需要通过函数变量名来调用。
三、函数参数
function 函数名称(形参列表){
函数体
}
函数名称(实参列表);
示例:
<script>
function add(a, b) {
console.log(a, b);
return a + b;
}
var result = add(2, 3); //2 3
console.log(result); //5
result = add(4, 6, 9); // 4 6
console.log(result); //10
result = add(5); //5 undefined
console.log(result); //5+undefined=NaN
</script>
运行结果:
注意:
(1)形参不需要var声明变量,否则会报错;
(2)函数声明可带参数也可不带参数;
(3)声明函数时括号内是形参,形参的默认值为 undefined;
(4)调用函数时括号内是实参 ;
(5)多个参数之间用英文逗号分隔;
(6)当实参与形参个数不匹配时结果不可预计,因此尽量要匹配 。
四、返回值
function 函数名(形参列表) {
函数体;
return 语句
}
示例:
<script>
function sub(a, b) {
return a - b;
}
var result = sub(3, 1);
console.log(result); //2
function fn(s) {
console.log(s);
return;
}
result = fn('hello'); //hello
result = fn(); // undefined
</script>
注意:
(1)当函数执行到 return 语句时,会结束函数执行并返回指定的值 ;
(2)如果函数无须返回值,也可以有 return 语句,但 return 后不能跟别的值 ;
(3)如果函数没有 return 语句,返回的值是 undefined。
五、函数的内部属性
5.1、arguments
在 JavaScript 的函数中 arguments 属性封装了函数的实参。
arguments说明:
(1)arguments是一个伪数组对象,它不是数组类型,可用 instanceof 运算符查看;
(2)当调用函数时,所传递的实参都保存在 arguments 中 ;
(3)可通过 arguments 对象的 length 属性来获取实参个数 ;
(4)arguments[0] 表示第一个实参,arguments[1] 表示第二个实参,以此类推;
(5)arguments 中有一个 callee 属性,它是一个函数对象,指向当前所使用的函数;
(6)只有函数才有arguments 对象,而且每个函数都内置好了这个arguments。
伪数组说明:伪数组并不是真正意义上的数组
(1)伪数组具有数组的lenght属性;
(2)伪数组可以按照索引方式进行存储;
(3)伪数组没有真正数组的一些方法pop()、push()等。
示例:
<script>
function add(a, b) {
// console.log(arguments);//里面存储了所有传递过来的实参
// console.log(typeof arguments);//object
// console.log(arguments instanceof Array); // false
// console.log(arguments instanceof Object);// true
// console.log(arguments.length);//8
// console.log(arguments[5]);//7
// 实现简单加法
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
// console.log(arguments[i]);
sum = sum + arguments[i];
}
console.log(sum);//44
}
add(2, 3, 4, 5, 6, 7, 8, 9);
</script>
5.2、this
<button>按钮</button>
<script>
// this 指向问题 一般情况下this的最终指向的是那个调用它的对象
// 1、全局作用域或者普通函数中的this指向全局对象window(注意定时器里面的this指向window)
console.log(this); //window
function fn() {
console.log(this); //window
}
fn();
window.setTimeout(function() {
console.log(this); //window
}, 1000)
// 2、方法调用中谁调用this指向谁
var obj = {
say: function() {
console.log(this); //obj
}
}
obj.say();
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
console.log(this); //btn
})
// 3、构造函数中this指向函数的实例
function Fun() {
console.log(this); //this指向的是fun实例对象
}
var fun = new Fun();
</script>
注意:
(1)全局作用域或者普通函数中的this指向全局对象window(注意定时器里面的this指向window);
(2)方法调用中谁调用this指向谁;
(3)构造函数中this指向函数的实例。
六、函数的方法
6.1、call()
函数名称.call();
示例:
<script>
window.color = 'red';
var obj = {
color: 'blue'
}
function show() {
console.log(this.color);
}
show(); // red
show.call(this); // red
show.call(window); // red
show.call(obj); // blue
function add(a, b) {
return a + b;
}
//console.log(window)
var result = add(2, 3);
console.log(result);
// 通过 call() 方法来调用函数
result = add.call(this, 1, 8);
console.log(result); //9
result = add.call(window, 2, 5);
console.log(result); //7
result = add.call(add, 3, 4);
console.log(result); //7
</script>
注意:当使用函数的 call() 方法调用时,方法的第一个参数是函数对象,如果有参数,则从 第二个位置开始依次提供。
6.2、apply()
函数名.apply();
示例:
<script>
window.color = 'red';
var obj = {
color: 'blue'
}
function show() {
console.log(this.color);
}
show(); // red
show.apply(this); // red
show.apply(window); // red
show.apply(obj); // blue
console.log('------------------');
function add(a, b) {
return a + b;
}
var result = add(2, 3);
console.log(result);
result = add.apply(this, [1, 3]);
console.log(result);
result = add.apply(window, [4, 5]);
console.log(result);
result = add.apply(add, [4, 6]);
console.log(result);
console.log('----------------');
var color = 'green';
</script>
注意:
(1)apply() 方法在这点的应用和 call() 方法没有区别,都是可以通过第一个参数来改变引用象。
(2)apply() 方法需要将实参封装到一个数组中统一传递。第一个参数是函数对象,第二个参数是数组,里面封装了参数。
<script>
function print() {
'use strict'; // 指定严格模式
console.log(this);
console.log(this.color);
}
// print.call(null);
//print.apply(undefined);
</script>
注意:
(1)在严格模式下,函数的指向始终是指定的值;
(2)在非严格模式下,如果使用call()或者apply()方法,传入null或者undefined会转换成一个全局的window对象。
6.3、call()和apply()的应用
6.3.1、找出数组中的最大的元素
<script>
var arr = [5, 20, 8, 51, 13];
// 找出数组中的最大的元素
var maxVal = Math.max(arr);
console.log(maxVal); //NaN
var maxVal = Math.max(5, 20, 8, 51, 13);
console.log(maxVal); //51
maxVal = Math.max.apply(this, arr); //this=Math.max
console.log(maxVal); //51
maxVal = Math.max.apply(this, [5, 20, 8, 51, 13]); //this=Math.max
console.log(maxVal); //51
</script>
6.3.2、将伪类数组转换为真正的数组
<script>
function add() {
console.log(arguments); //Arguments(3)
console.log(arguments instanceof Array); //false
// Array.prototype原型 slice复制
var arr = Array.prototype.slice.apply(arguments);
console.log(arr); //Array(3)
console.log(arr instanceof Array); //ture
}
add(1, 2, 3);
</script>
6.3.3、数组追加
<script>
var arr = [];
Array.prototype.push.apply(arr, [1, 2, 3, 4, 5]);
console.log(arr);
Array.prototype.push.call(arr, 4, 5, 6);
console.log(arr);
</script>
6.3.4、利用 call 和 apply 做继承
<script>
function Animal(name, age) {
this.name = name;
this.age = age;
this.show = function() {
console.log(this.name, this.age);
};
}
function Cat(name, age) {
// 继承
Animal.call(this, name, age);
}
var cat = new Cat('波斯猫', 3);
cat.show(); //波斯猫, 3
function Dog(name, age) {
//Animal.apply(this, [name, age]);//可以
Animal.apply(this, arguments);
}
var dog = new Dog('沙皮狗', 2);
dog.show();
</script>
6.4、bind()
<script>
function fun(y) {
console.log(this);
return this.x + y;
}
var obj = {
x: 2
}
//console.log(fun(3));
var fn = fun.bind(obj);//bind()返回一个新的函数fn
console.log(fn(4));
</script>
<script>
function getConf(color, size, other) {
console.log(color, size, other);
}
var fn = getConf.bind(null, '#ff0000', '500px');
fn('scrollTop');
fn('display')
</script>
七、立即执行函数
7.1、定义语法
(function(){
函数体;
})();
或者
(function(){
函数体;
}());
<script>
function fn(a) {
console.log('hello ' + a);
}
fn('hi');
// 立即执行函数
(function(){
console.log('world')
})();
(function () {
console.log('hi')
}())
var r = (function (a, b) {
console.log(a, b);
return a + b;
})(1, 2);
console.log(r);
</script>
7.2、立即执行函数应用
<script>
// 需求:每次调用 add,都返回加 1 的数字(初始值为 0)
// 1. 使用之前的方式来实现
function add() {
return ++add.count; // 给 add 函数对象指定了一个自定义的属性 count, 用于共享数据
}
add.count = 0;
console.log(add()); //1
console.log(add()); //2
console.log(add()); //3
// 2. 使用立即执行函数来实现
var rs = (function() {
var count = 0;
// 在立即执行函数中声明了一个变量
return function() {
return ++count;
};
})();
console.log(rs()); //1
console.log(rs()); //2
console.log(rs()); //3
</script>
2、现有如下程序,看看发生了什么问题,如何解决
<script>
function fn() {
var arr = [];
for (var i = 0; i < 5; i++) {
arr[i] = function() {
return i;
}
}
return arr;
}
var f = fn();
console.log(f);
console.log(f[0]());
console.log(f[1]());
</script>
使用立即执行函数
<script>
function fun() {
var arr = [];
for (var i = 0; i < 5; i++) {
(function(n) {
arr[n] = function() {
return n;
}
})(i);
}
return arr;
}
f = fun();
console.log(f);
console.log(f[0]());
console.log(f[1]());
console.log(f[4]());
</script>