第4章 变量、作用域和内存问题(2)

本文探讨了JavaScript中函数参数的传递方式,包括基本类型与引用类型的差异,并介绍了如何使用typeof和instanceof操作符进行类型检测。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4.1.3 传递参数

ECMAScript 中所有函数的参数都是按值传递的。也就是说,

把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。

基本类型值的传递如同基本类型变量的复制一样,而引用类型值的传递,则如同引用类型变量的复制一样。

有不少开发人员在这一点上可能会感到困惑,因为访问变量有按值和按引用两种方式,而参数只能按值传递。

在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(即命名参数,

或者用ECMAScript 的概念来说,就是arguments 对象中的一个元素)。在向参数传递引用类型的值时,会把

这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部。请看下面

这个例子:


<!DOCTYPE html>
<html>
<head>
    <title>Function Arguments Example 1</title>
    <script type="text/javascript">
        function addTen(num) {
            num += 10;
            return num;
        }
        
        var count = 20
        var result = addTen(count);
        alert(count);    //20
        alert(result);   //30

    </script>
</head>
<body>

</body>
</html>

这里的函数addTen()有一个参数num,而参数实际上是函数的局部变量。在调用这个函数时,变

量count 作为参数被传递给函数,这个变量的值是20。于是,数值20 被复制给参数num 以便在addTen()

中使用。在函数内部,参数num 的值被加上了10,但这一变化不会影响函数外部的count 变量。参数

num 与变量count 互不相识,它们仅仅是具有相同的值。

假如num 是按引用传递的话,那么变量count的值也将变成30,从而反映函数内部的修改。当然,使用数值等基本类型值来说明按值

传递参数比较简单,但如果使用对象,那问题就不怎么好理解了。再举一个例子:


<!DOCTYPE html>
<html>
<head>
    <title>Function Arguments Example 2</title>
    <script type="text/javascript">
        function setName(obj) {
            obj.name = "Nicholas";
        }
        
        var person = new Object();
        setName(person);
        alert(person.name);    //"Nicholas"

    </script>
</head>
<body>

</body>
</html>

以上代码中创建一个对象,并将其保存在了变量person 中。然后,这个变量被传递到setName()

函数中之后就被复制给了obj。在这个函数内部,obj 和person 引用的是同一个对象。换句话说,即

使这个变量是按值传递的,obj 也会按引用来访问同一个对象。于是,当在函数内部为obj 添加name

属性后,函数外部的person 也将有所反映;因为person 指向的对象在堆内存中只有一个,而且是全

局对象。有很多开发人员错误地认为:在局部作用域中修改的对象会在全局作用域中反映出来,就说明

参数是按引用传递的。为了证明对象是按值传递的,我们再看一看下面这个经过修改的例子:


function setName(obj) {
     obj.name = "Nicholas";
     obj = new Object();
     obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"

这个例子与前一个例子的唯一区别,就是在setName()函数中添加了两行代码:一行代码为obj

重新定义了一个对象,另一行代码为该对象定义了一个带有不同值的name 属性。在把person 传递给

setName()后,其name 属性被设置为"Nicholas"。然后,又将一个新对象赋给变量obj,同时将其name

属性设置为"Greg"。如果person 是按引用传递的,那么person 就会自动被修改为指向其name 属性值

为"Greg"的新对象。但是,当接下来再访问person.name 时,显示的值仍然是"Nicholas"。这说明

即使在函数内部修改了参数的值,但原始的引用仍然保持未变。实际上,当在函数内部重写obj 时,这

个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。

PS:可以把ECMAScript 函数的参数想象成局部变量。

4.1.4 检测类型

要检测一个变量是不是基本数据类型?typeof 操作符是最佳的工具。说得更具体一点,

typeof 操作符是确定一个变量是字符串、数值、布尔值,还是undefined 的最佳工具。如果变

量的值是一个对象或null,则typeof 操作符会像下面例子中所示的那样返回"object":


<!DOCTYPE html>
<html>
<head>
    <title>Determining Type Example 1</title>
    <script type="text/javascript">
        var s = "Nicholas";
        var b = true;
        var i = 22;
        var u;
        var n = null;
        var o = new Object();
        
        alert(typeof s);   //string
        alert(typeof i);   //number
        alert(typeof b);   //Boolean
        alert(typeof u);   //undefined
        alert(typeof n);   //object
        alert(typeof o);   //object

    </script>
</head>
<body>

</body>
</html>

虽然在检测基本数据类型时typeof 是非常得力的助手,但在检测引用类型的值时,这个操作符的用处不大。

通常,我们并不是想知道某个值是对象,而是想知道它是什么类型的对象。为此,ECMAScript

提供了instanceof 操作符,其语法如下所示:

result = variable instanceof constructor

如果变量是给定引用类型(根据它的原型链来识别;第6 章将介绍原型链)的实例,那么

instanceof 操作符就会返回true。请看下面的例子:

alert(person instanceof Object); // 变量person 是Object 吗?

alert(colors instanceof Array); // 变量colors 是Array 吗?

alert(pattern instanceof RegExp); // 变量pattern 是RegExp 吗?

根据规定,所有引用类型的值都是Object 的实例。因此,在检测一个引用类型值和Object 构造

函数时,instanceof 操作符始终会返回true。当然,如果使用instanceof 操作符检测基本类型的

值,则该操作符始终会返回false,因为基本类型不是对象。

PS:使用typeof 操作符检测函数时,该操作符会返回"function"。在Safari 5 及

之前版本和Chrome 7 及之前版本中使用typeof 检测正则表达式时,由于规范的原

因,这个操作符也返回"function"。ECMA-262 规定任何在内部实现[[Call]]方法

的对象都应该在应用typeof 操作符时返回"function"。由于上述浏览器中的正则

表达式也实现了这个方法,因此对正则表达式应用typeof 会返回"function"。在

IE 和Firefox 中,对正则表达式应用typeof 会返回"object"。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZHOU_VIP

您的鼓励将是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值