函数创建
函数的最大作用是提供代码复用,将需要重复使用的代码块定义成函数,提供更好的代码复用。函数可以有返回值,可以没有返回值。
let test = new Function("a","b","return a + b");
//参数a和b,函数体 return a + b
console.log(test(1,2));//3
② 函数表达式
let test = function(a,b){
return a + b;
}
console.log(test(1,2));
③ 函数声明
function test(a,b){
return a + b;
}
console.log(test(1,2)); //3
console.log(test.name); //test
函数表达式和函数声明的区别在于使用函数声明这种方式会使函数的声明提前,类似变量申明的提前。也就是说,使用函数申明方式,可以将函数的声明放在调用函数代码的后面,因为解析器会在代码执行之前将函数的声明提升到顶部,而函数表达式方式则会报错:
console.log(test(1,2));//3
//创建函数(函数申明方式)
function test(a,b){
return a + b;
}
console.log(ntest(1,2));
//创建函数(函数表达式方式)
let ntest = function (a,b){return a + b;}
//报错:ReferenceError: ntest is not defined
函数调用
let myObject = {
value : 3,
func : function(){
console.log(this.value);
}
};
// 方法调用模式,this对应的是myObject对象
myObject.func(); //3
② 函数调用模式
function add(a, b) {
return a + b;
}
this.add(3,4); //函数调用模式 7
//或者:
window.add = function(a, b) { return a + b; }
this.add(3,4); //7
③ 构造器调用模式
function add(a,b) {
this.sum = a + b;
}
// 构造器调用模式
let obj = new add(3,4);
console.log(obj); //add {sum: 7}
console.log(obj.sum); //7
④ call/apply调用模式
在第七章对象中的this关键字小节中有讲到,这里不做赘述。
函数的形参和实参
let num_1 = 10;
let arr_1 = ["Tom", "Peter", "Smith"];
let setInfo = function(num, arr){
num = 20;
arr[1] = "Jackson";
console.log(num);
console.log(arr);
}
console.log(num_1); //10
console.log(arr_1); //["Tom", "Peter", "Smith"]
setInfo(num_1,arr_1); //20 ["Tom", "Jackson", "Smith"]
console.log(num_1); //10
console.log(arr_1); //["Tom", "Jackson", "Smith"]
function m(x,y,z){
return x + y + z;
}
m(1,2) //NaN
m(1,2,3,4) //6
形参和实参的区别
作为值的函数
//声明一个函数
function square(x){ return x*x; }
//函数对象作为值赋值给其他变量
let fun = square;
fun(4); //16
let fun1 = square(4);
console.log(fun1); //16
//将函数直接作为对象直接量的属性或者数组的元素
let o = {x : 4, square : function(x){ return x*x; }}
o.square(o.x); //16
let a = [function(x){ return x*x; }, 'hello', 4]
a[0](a[2]) //16
//函数作为参数传入其他的函数
function add(x, y){ return x+y; }
function multiply(x, y){ return x*y; }
function operate(calculate, x, y){
return calculate(x,y)
}
operate(add,21,15) //36
operate(multiply,7,9) //63
函数不是原始值,是一种特殊的对象,所以它也可以有属性。当函数需要一个 “静态”变量来调用时保持某个值不变,最方便的方式就是给函数定义属性,而不是定义全局变量,显然定义全局变量会让命名空间变得更加杂乱无章。
闭包
function A(){
function B(){
console.log('Hello Closure!');
}
return B;
}
let C = A();
C(); // Hello Closure!
这是一个最简单的闭包示例,在上述代码中函数A的内部函数B被函数A外的一个变量 C 引用,所以当一个内部函数被其外部函数之外的变量引用时,就形成了一个闭包。
function A() {
let count = 0;
function B() {
count ++;
console.log(count);
}
return B;
}
let C = A();
C();// 1
C();// 2
C();// 3
上面代码中, count 是函数A 中的一个变量,它的值在函数B 中被改变,函数 B 每执行一次,count 的值就在原来的基础上累加 1 。因此,函数A中的 count 变量会一直保存在内存中。当我们需要在模块中定义一些变量,并希望这些变量一直保存在内存中但又不会 “污染” 全局的变量时,就可以用闭包来定义这个模块。
再看看下面的代码,使你更加明白闭包的作用:
function A() {
let count = 0;
function B() {
count ++;
console.log(count);
}
return B(); //此处加上小括号
}
let C = A();
C(); // Uncaught TypeError: C is not a function
let D = A;
D(); //1
D(); //1
D(); //1
函数属性,方法和构造函数
function sum(x, y, z) {
return x + y + z;
}
sum.length //3
prototype属性
//待绑定的函数
function f(y){
return this.x + y;
}
let o = {x : 2}; //这个是将要绑定的对象
let p = f.bind(o); //将o中的x绑定到f()中的this.x,这里必须同名;
p(3); //输出的是 5
let q = {y : 2};
let r = f.bind(q);
r(3); //NaN
ES5中的bind()方法不仅仅是将函数绑定到一个对象,还附带一些其他应用:除了第一个参数之外,传入bind()的实参也会绑定到this:
let sum = function(x,y){
return x + y;
};
let suc = sum.bind(null, 1); //this的值绑定到null,第一个参数x的值绑定到1
suc(2) //传入第二个参数得到计算结果 3
function f(y , z){
return this.x + y + z;
}
//this绑定到对象{x : 1},第一个参数绑定到2
let g = f.bind({x : 1},2);
g(3) //传入第二个参数得到计算结果 6