JavaScript--值类型和引用类型

原地址:https://blog.csdn.net/mapbar_front/article/details/78447136

1、引言

很多人都说,值类型无非就是JavaScript的五种基本数据类型- Undefined、 Null 、Boolean 、 Number、 String。引用类型就无非是Object、 Array。而它们就像你说的如此简单吗?

var a = 1;
a.name = 'mapbar_front';//这个会不会报错?
console.log(a.name);//结果undefined,那么这是为什么?
  • 1
  • 2
  • 3

2、值类型和引用类型的特点

(1)、概念描述

JavaScript是这样定义值类型的:代表一些简单的数据段,可以直接操作保存在一个变量的具体数值。

相反,对于引用类型,JavaScript这样定义:它代表一个对象,你能操作的仅仅是这个对象的引用。

var a = 1;
var b = a;//这句代码的意思就是var b = 1;也就是说,b = a就代表着把a中代表的值赋给b。
b = 2;
console.log(a);//1 也就是给b赋值的时候,a的值不受影响。
  • 1
  • 2
  • 3
  • 4

本质上,值类型的赋值操作是重新创建了一个内存空间。这里代表a和b分别在内存中有两个值为 1 的内存空间。

var a = new Object();
a.name = 'mapbar_front';
var b = a;//这里赋值的是a的引用。
b.name = 'JavaScript';
console.log(a.name);//JavaScript,表示给b对象添加属性name的时候,a对象的name属性也变了
  • 1
  • 2
  • 3
  • 4
  • 5

引用类型的本质,在赋值上是一个指向内存对象的一个指针。它在执行b = a的过程中,并没有创建新的内存空间

(2)、值类型变量和引用类型变量的另一个重要特点

所有变量都可以给它添加属性和方法。但是只有引用类型的变量才起效果

//引用上面的一个示例
var a = 1;
a.name = 'mapbar_front';//添加属性
console.log(a.name);//undefined。不起作用

//对于引用类型的变量
var b = new Object();
b.name = 'mapbar_front';
console.log(b.name);//'mapbar_front'。添加属性成功
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3、参数的按值传递和按引用传递

(1)、描述

一定要切记-JavaScript的参数传递是按值传递

var a = 1function add(x){
    return ++x;
}
var b = add(a);
console.log(a,b);//a为1不变,b为2.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

所以说,虽然JavaScript看起来是这样,通过传递参数的方式,不改变这个传递的实参,即对外部变量不改变。但是有时候会发生下面的“奇怪”现象:

var obj = { name: 'mapbar_front'};
function getObject(obj){
    obj.name = 'JavaScript';
    return obj;
}
var obj2 = getObject(obj);
console.log(obj.name);//'JavaScript',是不是不科学????
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

所以,凡是引用类型的变量当做实参来传递给函数的时候,传递给的是一个对象的引用,在函数内部是可以改变外部的对象的!!

原因何在???因为内部的obj被赋值的是外部obj的一个引用,都指向同一个值为 { name: ‘mapbar_front’} 的内存地址。内部obj变量改变这个name,外部的也跟着改变。

这就引发了下面一个问题

(2)、参数传递的本质过程是什么?

参数传递的时候,函数会在其内部定义一个局部变量来接收传递过来的实参。示例如下。

var a = 1;
function add(a){
    return ++a;
}
add(a);
  • 1
  • 2
  • 3
  • 4
  • 5

相当于。。。

var a = 1;
add(a);//把1传入。
function add(){
    var a = a;//把外部的a的值赋值给局部变量a。
    ++a;//其实操作的是自己的局部变量。
    return a;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

(3)、到底什么叫按引用传递?

按值传递的本质是重新定义一个局部变量来接收实参,而按引用传递是不重新定义局部变量,还是对原先传递的那个变量进行操作。

var obj = { name: 'mapbar_front'};
function add(obj){
    obj.name = 'JavaScript';
    obj = new Object();
    obj.name = 'no JavaScript';
}
add(obj);
console.log(obj.name);//'JavaScript'。如果是按引用传递参数,这里打印出的应该是 'no JavaScript'。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这个也从侧面证明了,参数的传递是值传递,会在内部定义一个局部变量来接收参数。而不是按引用传递参数的。

(4)、这里给大家增加一个小小的面试题(对上面的小示例稍作修改)

var a = 1;
console.log(a);//1
function add(a){
    var b = ++a;
    console.log(a);//2,这个a是函数的局部变量
    return a;
}
var c = add(a);
console.log(a);//1,a是全局变量
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我的总结

1、JavaScript 的基本数据类型有五种- Undefined、 Null、 Numer、 String、 Boolean。

2、JavaScript 的引用数据类型有两种- Object、 Array。

3、基本数据类型的赋值是值传递,本质上是重新创建了一个新的内存空间,而引用数据类型的赋值是一个指向内存空间的指针,本质上还是原先的内存地址。

4、JavaScript的参数传递是按值传递。不是按引用传递。

5、由于JavaScript 的引用数据类型的特性,在编码中,如果我们需要在不改变原对象的基础上操作数据,可能就需要对对象进行clone。

一个关于对象 clone 的 JavaScript 函数封装:

//深度clone
function clone(obj) {
    if(arguments.length !== 1){
        throw new Error('parameter is undefined');
    }
    //如果是值类型,直接返回
    if(typeof obj !== 'object'){
        return obj;
    }
    //如果是Array类型
    if(obj instanceof Array){
        var arr = new Array();

        for(var i = 0, len = obj.length; i < len; i++){
            if(typeof obj[i] === 'object'){
                arr.push(clone(obj[i]));
            } else {
                arr.push(obj[i]);
            }
        }
        return arr;
    }
    //如果是Object类型
    if(obj instanceof Object){
        var current = new Object();
        for(var i in obj){
            if(typeof obj[i] === 'object'){
                current[i] = clone(obj[i]);
            } else {
                current[i] = obj[i];
            }
        }
        return current;
    }
    //如果是Null
    if(obj === null){
        return null
    }
    //如果是自己未知的类型
    throw new Error('not supported this type data!');
}

//测试代码
var obj = {"name":'liwudi',"arr":[1,5,'s','ss',[5,9,null],9]};
var obj2 = clone(obj);
console.log(obj2);

obj['arr'][4][0] = 'change';

console.log(obj2);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
//单层clone,或者说是浅克隆
function cloneOne(objValue) {
    if(arguments.length !== 1){
        throw new Error('parameter is undefined');
    }
    //如果是值类型,直接返回
    if(typeof objValue !== 'object'){
        return objValue;
    }
    //如果是Array类型
    if(objValue instanceof Array){
        var arr = new Array();
        for(var i = 0, len = objValue.length; i < len; i++){
            arr.push(objValue[i]);
        }
        return arr;
    }
    //如果是Object类型
    if(objValue instanceof Object){
        var obj = new Object();
        for(var i in objValue){
            obj[i] = objValue[i];
        }
        return obj;
    }
    //如果是Null
    if(objValue === null){
        return null
    }
    //如果是自己未知的类型
    throw new Error('not supported this type data!');
}
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页