在ECMAscript中,Function实际上是对象,每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,所以函数名实际上是一个指向函数对象的指针。
声明方式
1.普通声明方式
function foo(a, b) {
return a + b;
}
2.使用变量初始化函数
let foo = function (a, b) {
return a + b;
}
3.使用Function构造函数(不推荐,二次解析,第一次解析ECMA代码,再解析一次构造函数传入的字符串)
let foo = new Function('a', 'b', 'return a + b');
作为值的函数
也就是函数本身就是变量,可以作为参数传给另外一个函数。
栗子1:
function add(a, b) {
return a + b;
}
function sum(a, b) {
return a + b;
}
console.log(sum(add(5, 5), 10));
// 20 函数传递返回值
栗子2:
function add(a, b) {
return a(b);
}
function sum(a) {
return a + 10;
}
console.log(add(sum, 10));
// 20 函数做为值 而非返回值
函数内部属性
函数内部有两个特殊对象:argument和this,argument是类数组对象,包含传入函数中的所有参数,主要用途是保存函数参数。这个对象还有一个叫callee的属性,该属性是一个指针,指向这个argument对象的函数。
1. arguments
function foo(num) {
if (num <= 1) {
console.log(num);
return 1;
} else {
console.log(num);
return num * foo(num - 1);
// 4 * 3 * 2 * 1
}
}
console.log(foo(4));
// 4 3 2 1 24
console.log(foo(1));
// 1
类似上面这种在函数内部调用自己的函数,也叫做递归。但是以上函数如果改变foo函数名位fun,内部函数名没有改变,则会报错,如果递归的代码很长,很难更改。所以,我们可以使用arguments.callee来代替。
也就是将return num * foo(num - 1);
改为return num * arguments.callee(num - 1);
用callee调用自身,实现递归。
2. this
this是调用函数的作用域,当全局调用函数的时候,这时this指向window;
window.color = 'red';
//Window 对象表示浏览器中打开的窗口 表示全局 此处在window定义了一个全局变量color
function sayColor() {
return this.color;
//作用链查找问题以后再说
}
console.log(sayColor());
// red 访问全局变量color
let obj = {
color: 'blue',
sayColor
// ES6写法 此处用的是全局的sayColor函数
};
console.log(obj.sayColor());
// blue 对象打点调用函数,this指向了调用函数的这个对象
let foo = obj.sayColor;
console.log(foo());
// red
函数属性和方法
length属性
表示函数形参个数
function foo(a, b) {
return a + b;
}
console.log(foo.length);
prototype属性
prototype也就是原型,保存所有实例方法。这个属性会在后面面向对象继续深入介绍。prototype下有两个方法:apply()和call(),每个函数都包括这两个非继承(后面再说)而来的方法。这两个方法的用途都在特定的作用域,调用函数。实际上等于设置函数this指向。
apply
function foo(a, b) {
return a + b;
}
function fun(a, b) {
return foo.apply(this, [a, b]);
}
function fun2() {
return foo.apply(this, arguments);
}
console.log(fun(10, 10)); // 20
console.log(fun2(10, 10)); // 20
call
var color = 'red';
// let不可以的,以后再说吧
let obj = {color: 'blue'};
function foo() {
return this.color;
}
console.log(foo(this));
// red
console.log(foo());
// red
console.log(foo.call(obj));
// blue
两者都可以改变函数的作用域,只是传参方式不一样。apply传数组,call直接传参。但是他们并不是上面这样用的,后面说面向对象再进行学习。还有一个绑定作用域的方法,叫做bind可以查阅一下。
网友评论