Javascript与C#对变量的处理方式

 

先来看一下Javascript的情况(下面所说的基本类型和简单类型是一个意思):

Javascript中变量会存在两种情况,一种是基本类型的,一共有五种,有null、Bollean、undefined、number、还有string。基本类型是指简单的数据段,这些类型的值是直接存储在变量中的,也就是说,访问变量是是直接访问变量中的值,是按值访问的。另外一种是引用类型,引用类型的值保存在内存中(堆),如果要访问引用类型的值,就要通过这个指向该对象的引用类型的变量来进行访问。Javascript不允许直接操作对象的内存空间。值得注意的时Js中的string类型是一个值类型。不论是值类型还是引用类型,Js中的变量只是一个保存值的名字,这个名字可以用来保存任意类型的值。定义一个变量后,这个变量可以随时随地的保存其他任何类型的值。简单类型的变量和引用类型的变量的区别在于复制的机制不同。复制一个基本类型的变量时会将原有变量的值重新复制一份,也就是说复制之后这两个时完全独立的,对一个进行操作不会引起另一个的改变。而复制一个引用类型的变量时,也是将变量中的值重新复制一份出来,不同的是引用类型的变量中包含的值就是一个指针,指向内存中(堆)真正的对象。也就是说复制后两个变量是共享一个对象,其中任何一个进行操作后都会去改变这个对象:

var obj1 = new Object();
var obj2 = obj1; 
obj1. name = "Nicholas"; 
alert( obj2. name); //"Nicholas"

传递参数方面JS都是按值进行传递的。

ECMAScript 中 所有 函数 的 参数 都 是按 值 传递 的。也就是说,把函数外部的值复制给函数内部的参数, 就和把值从一个变量复制到另一个变量一样。 基本类型值的传递如同基本类型变量的复制一样, 而引用类型值的传递, 则如同引用类型变量的复制一样。 有不少开发人员在这一点上可能会
感到困惑,因为访问变量有按值和按引用两种方式, 而参数只能按值传递。 泽卡斯(Zakas. Nicholas C.). JavaScript高级程序设计(第3版) (图灵程序设计丛书) (Kindle 位置 2623-2626). 人民邮电出版社. Kindle 版本.

  

 

在来看一下C#的情况:C#也包含两种数据类型,一种是简单数据类型,有byte、short、int、long、flaot、double、boolean、char等,这些简单数据类型都是简单数据类型,也叫做值类型,其值存储在变量本身,对这种类型的变量进行操作时会直接操作这个变量本身,与Js不同的是string是对象类型,值存储在堆上。另外一种就是对象类型,也叫做引用类型,对象是存储在堆上进行实例化后的一种叫法,当new一个对象类型时,会返回一个指向该对象的引用,这个引用(值)存储在一个栈上的变量中(有关实例化值类型变量后具体的存储位置,和值类型变量实例化的时机和地方有关。在C# in depth中有介绍。),也就是说,该变量的值保存的是一个引用,操作对象时都是通过这个引用来操作保存在堆上的对象。这个也就造成了C#中值类型和引用类型的根本区别在于复制的机制不同。在c#不论是值类型还是引用类型都可以进行按值传递和按引用传递,按值传递就是将变量的值进行一份拷贝,而按引用进行传递实际上是传递一个原有变量的“别名”,也就是说,按值传递的话操作的是另外一份数据,而按引用传递的话是操作的同一份数据,但是这个在值类型和引用类型中所引发的后果也是稍有不同的,值类型因为其值本身在变量中保存,如果按值进行传递的话那连同这个变量和值是一起被拷贝的,就是说在栈上另外开辟了一块空间来保存这个副本,那这样的话对原有的值是不会产生任何影响的。看下面的例子:

class Program
    {
        static void Main(string[] args)
        {
            int shit = 2;
            Console.WriteLine("before:"+shit);//返回2
            DoSome(shit);
            Console.WriteLine("after:"+shit);//返回2
            Console.WriteLine(DoSome(shit));//返回3
            Console.ReadKey();
        }

        public static int DoSome(int shit)
        {
            shit++;
            return shit;
        }
    }

  而如果按引用去传递一个值类型的变量,那么就是将原有变量起了一个别名后传递了出去,实际上“别名”和原有的变量共享了一份值。那么不论是对“别名”进行操作还是对原有变量进行操作都会改变值,看下面的例子:

class Program
    {
        static void Main(string[] args)
        {
            int shit = 2;
            Console.WriteLine("before:"+shit);//返回2
            DoSome(ref shit);
            Console.WriteLine("after:"+shit);//返回3
            Console.WriteLine(DoSome(ref shit));//返回4
            Console.ReadKey();
        }

        public static int DoSome(ref int shit)
        {
            shit++;
            return shit;
        }
    }

  上面说的都是C#中值类型的按值传递和按引用传递的区别。顺便说一下,C#中按引用传递分为ref和out,这两个关键字都是用来表示按引用进行传递,就是对实参的初始化的时机有所不同。一个是必须在使用前进行初始化(out),ref则没有这样的要求。

对于C#中引用类型的按值传递和按引用传递,又与值类型的按值传递和按引用传递的表现有所不同,引用类型的按值传递同理也是连变量带值都拷贝了一份,不同于值类型的是引用类型变量的值本身只是一个指向对象的引用,保存的是一个地址,所以引用类型的变量按值传递时也会有可能去改变堆上的变量,也有可能不会改变,比如将引用类型的变量按值传递出去之后马上对它进行一个new的操作,从而使它重新指向一个堆上的新地址。:)而对引用类型的变量进行按引用传递时同理也是其一个别名,这个别名和原来的对象都是共享一个值(指向堆上对象的引用)所以对这个别名进行的任何操作都会改变堆上的这个对象。

18:21:51

原文地址:https://www.cnblogs.com/pangjianxin/p/7738294.html