资讯专栏INFORMATION COLUMN

JavaScript引用类型——“Function类型”的注意要点

fantix / 3174人阅读

摘要:类型每个函数都是类型的实例。如以上代码可行,是因为在代码开始值钱,解析器就已经通过一个名为函数声明提升的过程,读取并将函数声明添加到执行环境中去。也可同时使用函数声明和函数表达式,但在浏览器中会出错。

Function 类型

每个函数都是Function 类型的实例。函数名实际上就是一个指向函数对象的指针,不会与某个函数绑定。

函数声明方式创建Function,语法如下:

function sum(x,y){
    return x + y;
}

函数表达式定义Function,用var 如下:

var sum = function(x,y){
    return x + y;
};

第二种方法不要忘记在结尾加上分号

另外还可以使用Function 构造函数。如:

var sum = new function("x","y","return x + y");

非常不推荐使用这种形式。

如何证明函数名仅仅是指向函数的指针呢:

var sum = function(x,y){
    return x + y;
};
console.log(sum(1,2)); //3

var anotherSum = sum;
console.log(anotherSum(1,1)); //2

sum = null;
console.log(anotherSum(10,10)); //20
没有重载

同名的后面的函数将会覆盖前面的函数。如:

function add(num){
    return num + 100;
}
function add(num){
    return num + 200;
}
console.log(add(100)); //300

用另外一种写法就可以很清楚的看出原因。如:

var add = function(num){
    return num + 100;
}
add = function(num){
    return num + 200;
}
console.log(add(100)); //300
函数的声明与函数表达式(以及函数声明提升)

解析器会率先读取函数声明,并使其在执行任何代码之前可用(可访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。如:

console.log(sum(1,1)); //2
function sum(x,y){
    return x + y;
}

以上代码可行,是因为在代码开始值钱,解析器就已经通过一个名为函数声明提升(function declaration hoisting)的过程,读取并将函数声明添加到执行环境中去。即使声明函数的代码在调用它的代码后面,JavaScript 引擎也能把函数声明提升到顶部。

但是,如果把函数声明改成函数表达式,则会导致错误。如:

console.log(sum(1,1)); 
var sum = function(x,y){
    return x + y;
}; //TypeError: undefined is not a function (evaluating "sum(1,1)")

失败的原因就在于函数位于初始化语句中,而不是一个函数声明。

也可同时使用函数声明和函数表达式,但在safari 浏览器中会出错。

作为值的函数

函数也可以作为值来使用,也就是可以将一个函数作为另一个函数的结果返回。如

function callFunction(someFunction,someArgument){
    console.log(someFunction(someArgument));
}
function addNum(x){
    return x + 100;
}
callFunction(addNum,100); //200

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

function compare(func,x,y){
    var num1 = func(x);
    var num2 = func(y);
    var array = [num1,num2];
    
    var result = array.sort(sortFunc);
    console.log(result.toString());
    document.write(result.join(" then "));
    
    
    function sortFunc(value1,value2){
        if (value1 > value2){
            return 1;
        }else if(value2 > value1){
            return -1;
        }else{
            return 0;
        }
    }
}

function add10(num){
        return num + 10;
    }

compare(add10,10000,999100); //10010 then 999110
函数内部属性

这里主要说一下callee属性、this属性以及caller属性。

callee属性的功能就是消除函数名的耦合问题。如:

function min(num){
    if(num == 1){
        return 1;
    }else if(num < 1){
        return 0;
    }else{
        return min(num - 1);
    }
}

var result = min(100);
document.write(result);

上面这个min()函数如果改了函数名,函数里面也相应的需要修改函数名。但添加了callee属性,就不需要修改。如:

function mins(num){
    if(num == 1){
        return 1;
    }else if(num < 1){
        return 0;
    }else{
        return arguments.callee(num - 1);
    }
}

var result = mins(100);
document.write(result);

着就解决了耦合现象所带来的问题。

this这个特殊对象的作用与Java 和C# 中的this 类似。this引用的是函数据以执行的环境对象——或者this值。如:

window.color = "red";
var obj = {color: "yellow"};

function show(){
    document.write(this.color);
}

show(); //red

obj.show = show;
obj.show(); //yellow

caller用来调用当前函数的函数的引用(源代码)。如:

function sum(x,y){
    plus(x,y);
}

function plus(x,y){
    console.log(x + y);
    document.write("
" + plus.caller + "
"); } sum(10,20);

如:

(
    function a(){
        document.write("function a");
        b();
        function b(){
            document.write("function b");
            alert(arguments.callee.caller);
        }
    }
)()

用arguments.callee 可能在某些浏览器中会导致错误:

function sum(x,y){
    plus(x,y);
}

function plus(x,y){
    console.log(x + y);
    document.write("
" + arguments.callee.caller + "
"); } sum(10,20);
函数属性和方法

每个函数都包含两个属性lengthprototype

length属性中,将返回参数的个数。如:

function colors(color1,color2){
    var array = [color1,color2];
    document.write(array.join("/"))
}
colors("red","blue");
document.write(" " + colors.length + "个参数"); //red/blue 2个参数

又如:

function toStr(){
        var result = "";
        for (var i = 0; i < arguments.length; i ++){
            result += arguments[i].toString() + " ";
        }
        document.write(result);
        document.write(" " + arguments.length + "个参数" + "
"); document.write(" " + arguments.callee.length + "个函数期望参数"); } toStr(321,32,43243,432,3213); /* 321 32 43243 432 3213 5个参数 0个函数期望参数 */

prototype属性。这个属性是保存它们所有实例方法的真正所在。在创建自定义引用类型以及实现继承时,这个属性是非常重要的(以后再多带带讨论)。另外,在ECMAScript 5 中,这个属性不可枚举(不能用for-in)。主要的两个非继承方法有apply()call();这两个方法的用途都是在特定的作用域中调用函数。

apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。第二个参数可以是Array 的实例,也可以是arguments 对象。如:

function sum(x,y){
    document.write(x.toString() + y.toString());
}

function plus(){
    return sum.apply(this,arguments);
}

plus(321,"fff");

下面这个则是Array 的实例:

function sum(x,y){
    document.write(x.toString() + y.toString());
}

function plus(a,b){
    return sum.apply(this,[a,b]);
}

plus(321,"fff"); 

call()方法与前者的作用相同,区别在于接收参数的方式不同。第二个参数必须一个个列举出来。如下:

function sum(x,y){
    document.write(x.toString() + y.toString());
}

function plus(a,b){
    return sum.call(this,a,b);
}

plus(321,"fff");

上面例子中plus(a,b) 不能写成plus();call(this,a,b)不能写成call(this,arguments)call(this,[a,b])

高能!!!

高能!!!

事实上,apply()call()真正有价值的用途是扩充函数的作用域。如:

var child = {
    name: "Oliver",
    age: 18
}
var adult = {
    name: "Troy",
    age: 24
}

function showName(){
    document.write(this.name);
}

showName.call(adult); //Troy
showName.call(child); //Oliver

使用上面这两个方法来扩充作用域的最大好处就是对象不需要与方法又任何耦合关系。

ECMAScript 5 还定义了一个方法:bind()。this 的值会被绑定到传给bind()函数的值。如:

var child = {
    name: "Oliver",
    age: 18
}
var adult = {
    name: "Troy",
    age: 24
}

function showName(){
    document.write(this.name);
}

var newFunc = showName.bind(child);
newFunc(); //Oliver

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86230.html

相关文章

  • Javascript变量注意要点

    摘要:如很明显可以看到,实际上是函数的局部变量。简单的说就是,复制给参数,在函数内部是局部变量,无论怎么变化,都不影响的变化。 ECMAScript 变量可能包含两种不同数据类型的值:基本类型值和引用类型值。 基本类型和引用类型的值 基本类型值(String,Number,Boolean,Null,Undefined)指的是简单的数据段;引用类型值(保存在内存中的对象)指的是那些可能由多个值...

    booster 评论0 收藏0
  • Javascript引用类型——“Object类型注意要点

    摘要:类型关于引用类型的概念引用类型引用类型的值对象是引用类型的一个实例对象是某个特定引用类型的实例新对象用操作符后跟一个构造函数来创建的如代码这行代码创建了引用类型的一个新实例,然后把该实例保存在了变量中。使用的构造函数是。 Object 类型 关于引用类型的概念: 引用类型:引用类型的值(对象)是引用类型的一个实例; 对象:是某个特定引用类型的实例; 新对象:用new 操作符后跟一个构...

    Codeing_ls 评论0 收藏0
  • JavaScript引用类型——“单体内置对象”注意要点

    摘要:单体内置对象单体内置对象就是开发人员不必显式地实例化内置对象,因为他们已经实例化了。前面的章节讨论过了大多数内置对象,还定义了两个单体内置对象和。 单体内置对象 单体内置对象就是开发人员不必显式地实例化内置对象,因为他们已经实例化了。前面的章节讨论过了大多数内置对象,ECMA-262 还定义了两个单体内置对象:Global 和Math。 Global 对象 所有在全局作用域中定义的属性...

    xushaojieaaa 评论0 收藏0
  • JavaScript 代码优化和部署——“可维护性”注意要点

    摘要:代码约定可读性以下地方需要进行注释函数和方法注释参数代表什么,是否有返回值大段代码描述任务的注释复杂的算法变量和函数命名变量用名词函数名用动词开头等返回布尔值类型的函数用等合乎逻辑不用担心太长变量类型透明化方法一初始化,如下推荐方法二匈牙利 代码约定 可读性 以下地方需要进行注释: 函数和方法:注释参数代表什么,是否有返回值; 大段代码:描述任务的注释; 复杂的算法; Hack 变...

    scwang90 评论0 收藏0
  • JavaScript引用类型——“Date类型注意要点

    摘要:类型中的类型使用自,国际协调时间年月日午夜零时开始经过的毫秒数来保存日期。类型保存的日期能够精确到年月日之前或之后的年。和的输出因浏览器不同而有所差异如年月日上午方法可用比较操作符来比较日期值。 Date 类型 ECMAScript 中的Date 类型使用自UTC(Coordinated Universal Time,国际协调时间)1970 年1 月1 日午夜(零时)开始经过的毫秒数来...

    brianway 评论0 收藏0

发表评论

0条评论

fantix

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<