我是靠谱客的博主 高挑短靴,最近开发中收集的这篇文章主要介绍深入解剖JS 中只有按值传递,没有按地址(引用)传递3.函数参数的传递,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

数字、字符串:把值直接复制进去;数组、对象:把变量地址复制进去。

ECMAScript 中,所有函数的参数都是按值来传递的。基本类型值的传递和基本类型变量复制一致(采用在栈内新建值),引用类型值的传递和引用类型变量的复制一致(栈内存放的是指针,指向堆中同一对象

1.基本类型的传递

//在基本类型参数传递的时候,是复制栈帧的拷贝操作。外部声明的变量num和函数参数的num,拥有完全相同的值,但拥有完全不同的参数地址,两者谁都不认识谁,在函数调用返回的时候弹出函数参数num栈帧。所以改变函数参数num,对原有的外部变量没有一点影响。
function add(num){
   num+=10;
   return num;
}
num=10;
add(num);//20
num;//10

2.引用类型的传递

引用类型的值是什么东西?基本类型的数据是存放在栈内存中的,引用类型的数据是将栈内存中的数据存放在堆内存中的。

当变量b向变量a复制引用类型的值时,会将存储在变量a栈中的值(栈中存放的值是对应堆中的引用地址)复制一份到为新变量b分配的空间中。即复制操作结束后,两个变量实际上引用同一个对象。

千万不要认为,在局部作用域中修改的对象会在全局作用域中反映出来就说引用类型是按引用传递的。为了证明是值传递,例3可以很好的证明

//引用类型的值实际上是对其引用对象的一个指针
//例1:
var user = new Object();
var admin = user;
admin.name = "xiaoxiaozi";
user.name; //返回 xiaoxiaozi

//例2:
function setName(obj){
    obj.name="ted";
}
var obj=new Object();//创建了一个object对象,将其引用赋给obj
setName(obj);//在传递函数参数的时候,复制了一个栈帧给函数参数的obj,两者拥有相同的值即object对象的地址
obj.name;//ted

​//例3:
function setName(obj){
    obj.name="ted";
    obj=new Object();//obj 被重新赋值,引用的对象已经与 外部的obj 不同,所以后面设置的 name 属性,不会对 obj 引用的对象有任何影响。
    obj.name="marry";
}
var obj=new Object();
setName(obj);//person 被复制给了 obj ,因此在函数内部 obj 与 person 引用的是同一个对象,即是对同一个对象的引用
obj.name;//ted

引用数据类型的副本值的变化对原始值有什么影响??1、直接操作副本属性,会同时改变原始值有影响。2、操作副本时重新赋值,不会改变原始值无影响。我们可以看以下几个例子:

//让 v1、v2、v3 作为参数进入函数后,就有了地址副本,这些地址副本的指向和外部的 v1、v2、v3 的地址指向是相同的。但函数中为 v1、v2、v3 重新赋值,也就是把地址副本的指向改变了,指向了新的数组和对象。这样内部的 v1、v2、v3 和外部的 v1、v2、v3 的地址指向就不一样了,所以外部值不受印象。
var v1 = []
var v2 = {};
var v3 = {};
function foo(v1, v2, v3)
{
    v1 = [1];
    v2 = [2];
    v3 = {a:3}
}

foo(v1, v2, v3);
v1;//[]
v2;//{}
v3.a;//undefined

//如果在函数中直接操作它,那么函数内的变量和外部的 v1、v2、v3 的地址指向依然是相同的。这样内部变量的改变是会影响外部变量的值的。
function foo(v1, v2, v3)
{
    v1.push(1);
    v2.a = 2;
    v3.a = 3;
}
foo(v1, v2, v3);
v1;//[1]
v2.a;//2
v3.a;//3

再看另几个例子:

//例1:
var c1 = {v:1};
var c2 = c1;//c1栈中的地址复制给了c2
c2.v = 11;//直接操作c2的属性,会直接影响c1的属性
c2 = {v:2};//c2被重新赋值,即指向了新的地址
c1.v; // 显示 11
c2.v; // 显示 2
//例2:
function c()
{
    var obj = {v:1};
    obj.func = function()
    {
        obj.v = 2;
    };
    
    return obj;
}

var c1 = c();//new c()  因为c 中使用了 return直接返回obj,所以 new 不 new 都一样
c1.func();//函数内直接操作obj 的属性
c1.v; // 2  
//例3:
function c()
{
    var obj = {v:1};
    obj.func = function()
    {
        obj = {v:2};
    };
    
    return obj;
}

var c1 = c();
c1.func();//函数内obj被重新赋值,obj指向了新的地址,已经和外部的obj无关
c1.v; // 1
//例4:
function c()
{
    this.obj = {v:1};
    this.func = function()
    {
        this.obj = {v:2};
    };
}

var c2 = new c();
c2.func();
c2.obj.v; // 2 由于使用了 this表示的是当前的实例对象

3.函数参数的传递

//在向参数传递引用类型值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部。
function setName(obj){
    obj.name = "xiaoxiaozi";
}
var person = new Object();
setName(person);//person 被复制给了 obj ,因此在函数内部 obj 与 person 引用的是同一个对象,即是对同一个对象的引用
person.name; // xiaoxiaozi

千万不要认为,在局部作用域中修改的对象会在全局作用域中反映出来就说函数参数的传递是按引用传递的。为了证明是值传递,引用类型的传递中的例3可以很好的证明。

最后

以上就是高挑短靴为你收集整理的深入解剖JS 中只有按值传递,没有按地址(引用)传递3.函数参数的传递的全部内容,希望文章能够帮你解决深入解剖JS 中只有按值传递,没有按地址(引用)传递3.函数参数的传递所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部