一关于值传递和引用传递
JavaScript中只有值传递。
假设有引用ref引用到了对象obj,那么此时引用ref中的数据就是obj的地址。
按照值传递的观念,是把引用ref中存储的数据值,也即是obj的地址传递给一个函数。
按照引用传递的观念,是把引用ref传递给另一个函数,这里把引用传递个另一个函数实际上是把引用本身的地址(不是引用保存的数据值)传递给另一个函数。
值传递:
形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,
不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。
指针传递:
形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作
引用传递:
形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过
栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
二 问题的引出
如下一段JavaScript代码
$(function () {
var str="abc";
var obj=new String(str);
function newToString(){
return "hello,world";
}
function func(val){
val.toString=newToString();
}
func(str);
alert(str);
func(obj);
alert(obj);
})
上面的运行结果显示 两次都是输出 abc
三 ,解释说明
在上面的这段javascript代码中,我们分别创建了一个字符串值和一个字符串对象。然后分别将这两个数据传递到func方法中。
(1)对于字符串值str来说,调用func方法 的时候会将该值传递到函数中,
val.toString
这行代码首先是系统为str包装一个String对象,然后给该对象的toString属性赋值为newToString方法的返回值(表述不准确,见下文)。然后当这行代码执行结束之后这个包装string对象就被销毁了。因此在以后的代码中我们也没有办法或者这个系统包装生成的string对象。所以为这个包装对象设置的toString属性值也就没办法在以后代码中获取。
alert(str)的时候系统也会自动为str再次生成一个String包装对象,然后调用该包装对象的toString属性所以引用的方法,也就是调用了toString(),最终输出abc。
(2)对于obj对象来说,会复杂一些。
现在有一个问题需要思考,我们知道所有的js对象都有一个toString()方法,string类型的对象也有toString方法,按照我个人的理解toString实际上是js原型对象的一个属性,然后这个属性引用到了第一个方法,所以我们 可以直接调用toString()方法。
当我们调用方法func(obj)的时候会执行代码:
val.toString=newToString();
对这行代码的执行结果又两种理解:
a:因为对象obj的原型对象上面有toString属性,这个属性引用到了一个方法。所以这里的val.toString会定位到原型对象的toString属性,所以这行代码的执行效果就是对更改了原型对象的toString属性为
方法的返回值。
b: 为对象obj增添一个属性toString,而不更改原型属性
第一种效果中更改了原型对象的属性,会使得所有的string对象的toString属性都不再引用原有方法,而是引用到了newToString()方法的返回值。
在实际的运行中是采用了第二种方式,也即是为obj对象增添toString属性。原因是在原型继承中,可以通过实例访问原型的属性,但是不可以通过实例更改原型的属性。这样obj对象就增添了一个toString属性,并且他的
原型对象中存在着toString属性,该属性引用到了一个方法。
那么接下来的问题是:
alert(obj)是如何做到输出abc的?
按照我个人的理解,系统首先在obj上寻找toString属性,并且可以在实例对象obj上找到该属性,但是这个属性引用的是一个String对象,而不是方法,所以无法将其作为方法调用。然后系统会继续向上寻找一个类型为Function的
toString属性,可以在原型对象上面找到。所以会输出abc,而不是“helloworld”。
在这个过程中我们应该注意到obj有两个toString属性,一个是字符串对象,一个是原型对象上面的函数对象。在调用alert(obj)的时候可以准确定位调用到toString()函数。
四 补充扩展
修改代码如下:
function func(val){ val.toString=newToString; }
在上面的代码中我们景val的toString属性赋值为一个函数对象,而不是函数的返回值。然后调用 func(obj)和alert(obj),此时根据上面的讲解我们知道obj实例对象上有一个toString属性引用到了newToString函数,原型对象上
有toString属性应用到了另一个函数,所以在这里alert将会输出"helloword"
不喜欢写博客,太麻烦