美文网首页程序员让前端飞我爱编程
【JS基础】JavaScript引用类型之Function类型

【JS基础】JavaScript引用类型之Function类型

作者: 虹猫1992 | 来源:发表于2018-12-25 21:46 被阅读7次

每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。

一、定义函数

  1. 使用函数声明语法
function sum (num1, num2) {
    return num1 + num2;
}
  1. 使用函数表达式
// 在使用函数表达式定义函数时,变量sum 即可以引用函数,无需函数名
var sum = function(num1, num2){
    return num1 + num2;
}; // 注意函数末尾有一个分号,就像声明其他变量时一样
  1. 使用Function构造函数
var sum = new Function("num1", "num2", "return num1 + num2"); // 不推荐
  1. 定义函数注意事项

(1)函数声明与函数表达式的区别

  • 解释器会率先读取函数声明,并使其在执行之前可以访问;
  • 而使用表达式则必须等到解析器执行到它所在的代码行,才会真正被解释执行(变量声明提前,而值留在原地);
  • 除以上不同之外,函数声明与函数表达式两者是等价的。
alert(sum(10,10));
function sum(num1, num2){
    return num1 + num2;
}

↑以上代码会正常执行,因为在代码执行前,解析器通过函数声明提升,读取并将函数声明添加到执行环境中,放到代码树的顶部。

alert(sum(10,10)); // 报错
var sum = function(num1, num2){
    return num1 + num2;
};

↑以上代码报错,原因在于函数位于一个初始化语句中,不是一个函数声明,不会被提前,而只会把var sum提前,也就是在执行到函数所在的语句之前,变量sum 中不会保存有对函数的引用,所以会报错

(2)函数是对象,函数名是指针。由于函数名仅仅是指向函数的指针,因此函数名与包含对象指针的其他变量没有什么不同,也就是说,一个函数对象可以有多个名字

function sum(num1, num2){
    return num1 + num2;
}
alert(sum(10,10)); //20

var anotherSum = sum; // //变量anotherSum也指向了同一个函数对象
alert(anotherSum(10,10)); //20

sum = null; // //sum变量不再保存函数对象的指针了
alert(anotherSum(10,10)); //20,anotherSum这个变量仍能调用

二、没有重载的概念

function addSomeNumber(num){
    return num + 100;
}
function addSomeNumber(num) {
    return num + 200;
}
var result = addSomeNumber(100); //300

↑以上代码中,声明了两个同名函数,而结果则是后面的函数覆盖了前面的函数。以上代码实际上与下面的代码没有什么区别:

var addSomeNumber = function (num){
    return num + 100;
};
addSomeNumber = function (num) {
    return num + 200;
};
var result = addSomeNumber(100); //300

↑通过以上代码可知,在创建第二个函数时,实际上覆盖了引用第一个函数的变量addSomeNumber,所以不能重载。

三、作为值的函数

  • 因为函数名本身就是变量,所以函数也可以作为值来使用
  • 不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回。

(1)函数作为参数传递给另一个函数

要访问函数的指针而不执行函数的话,必须去掉函数名后面的那对圆括号。

function callSomeFunction(someFunction, someArgument){
    return someFunction(someArgument);
}

function add10(num){
    return num + 10;
}
var result1 = callSomeFunction(add10, 10);
alert(result1); //20

function getGreeting(name){
    return "Hello, " + name;
}
var result2 = callSomeFunction(getGreeting, "Nicholas");
alert(result2); //"Hello, Nicholas"

// 以上传递给callSomeFunction()的是 add10 和 getGreeting,而不是执行它们之后的结果。

(2)从一个函数中返回另一个函数

function createComparisonFunction(propertyName) {
    return function(object1, object2){
        var value1 = object1[propertyName];
        var value2 = object2[propertyName];
        if (value1 < value2){
            return -1;
        } else if (value1 > value2){
            return 1;
        } else {
            return 0;
        }
    };
}

var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];

data.sort(createComparisonFunction("name"));
alert(data[0].name); //Nicholas

data.sort(createComparisonFunction("age"));
alert(data[0].name); //Zachary

四、函数内部的属性

  1. arguments属性

arguments是个类数组对象,包含着传入函数的所有参数,这个对象有一个叫callee的属性,属性值是一个指针,指向拥有这个arguments对象的函数本身。

function foo (){
    var a =arguments.callee; // arguments.callee指foo函数本身    
    return a.toString();
}
foo();
/*
返回结果:
"function foo (){
    var a =arguments.callee;     
    return a.toString();
}"
也就是说,一个函数内部,arguments.callee指的就是这个函数本身。
这个函数在递归调用时有点用,有许多缺陷,在ES5严格模式被移除
*/
  1. this属性

this指的就是函数执行的环境对象,在哪个对象中执行,this就指哪个对象。当在网页的全局作用域中调用函数时, this 对象引用的就是 window

window.color = "red"; 
var o = { color: "blue" }; 

function sayColor(){ 
    alert(this.color); 
} 

sayColor();     //"red" 
o.sayColor = sayColor; 
o.sayColor();   //"blue" 
  1. caller属性

caller属性中保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为 null

function outer(){ 
    inner();  
} 
function inner(){ 
    console.log(inner.caller); 
} 

outer(); 
/*
输出结果:
ƒunction outer(){ 
    inner();  
}
*/

五、函数的属性和方法

  1. 函数的属性

(1)length属性:表示函数希望接收的命名参数的个数。

function sayName(name){ 
    alert(name); 
}       
function sum(num1, num2){ 
    return num1 + num2; 
} 
function sayHi(){ 
    alert("hi"); 
} 
console.log(sayName.length);      //1 
console.log(sum.length);          //2 
console.log(sayHi.length);        //0

(2)prototype属性:简单来说,是一个对象,是通过调用构造函数而创建的一个对象,包含可以由特定类型的所有实例共享的属性和方法

  1. 函数的方法

(1)applycall方法

  • 两个方法的作用都是在特定的作用域中调用函数,实际上就是设置函数内部的this;
  • apply():接收两个参数,一个是函数运行的作用域,另一个是参数数组,可以是数组,也可以是arguments这个类数组对象;
  • 在使用 call()方法时,传递给函数的参数必须逐个列举出来;
  • call()方法与 apply()方法的作用相同,它们的区别仅在于接收参数的方式不同
function sum(num1, num2){ 
    return num1 + num2; 
} 
function callSum1(num1, num2){ 
    return sum.apply(this, arguments);        // 传入 arguments 对象 
} 
function callSum2(num1, num2){ 
    return sum.apply(this, [num1, num2]);    // 传入数组 
} 
alert(callSum1(10,10));   //20 
alert(callSum2(10,10));   //20 

// 也可以使用 call()方法
function callSum(num1, num2){ 
    return sum.call(this, num1, num2); 
} 
alert(callSum(10,10));   //20 

至于是使用 apply() 还是 call(),完全取决于你采取哪种给函数传递参数的方式最方便。

传递参数并非 apply()call() 真正的用武之地;它们真正强大的地方是能够扩充函数赖以运行的作用域

window.color = "red"; 
var o = { color: "blue" }; 
function sayColor(){ 
    alert(this.color); 
} 

sayColor();                //red 
sayColor.call(this);       //red 
sayColor.call(window);     //red 
sayColor.call(o);          //blue,此时函数体内的 this 对象指向了 o

(2)bind()方法:这个方法会创建一个函数的实例,其 this 值会被绑 定到传给 bind() 函数的值

window.color = "red"; 
var o = { color: "blue" }; 
function sayColor(){ 
    alert(this.color); 
}  
var objectSayColor = sayColor.bind(o); 
objectSayColor();    //blue 

↑以上代码中,sayColor()调用 bind()并传入对象o,创建了objectSayColor()函数。objectSayColor()函数的 this 值等于 o,因此即使是在全局作用域中调用这个函数,也会看到"blue"

相关文章

网友评论

    本文标题:【JS基础】JavaScript引用类型之Function类型

    本文链接:https://www.haomeiwen.com/subject/ohbqlqtx.html