js 按值传递和按引用传递,函数按什么传递,如何理解?

基本数据类型按值传递
复杂数据类型按引用传递

请问:函数感觉也是复杂数据类型,但它的传递好像是按值传递的,这个该怎么理解呢

const fn1 = () => console.log(111)

let fn2 = fn1
fn2 = () => console.log(222)

// 如果引用传递的话,它俩的打印不应该都是222吗,但实际如下
fn1() // 111
fn2() // 222

// 或者有什么方式的赋值,能体现出来函数是引用传递的?
阅读 4.3k
9 个回答

function 是对象,按引用传递。

但是 JS 中的引用和 C++ 中的引用概念不同,它更接近于 C++ 的 const 指针的概念。所以对一个引用赋值只是改变了它的指向,并不会改变原变量。

所以我觉得可以这样理解,都是按值传递,只不过基本数据类型传递的是本身的值,而复杂数据类型传递的是引用(地址)的值。

你对引用传递可能存在一些误解;

obj1 = {a:1} 的时候,计算机会为 {a:1} 开辟内存空间,并把 {a:1} 存入其中,之后会把所存内存空间的起始地址赋值给 obj1, 也就是 obj1 在计算机里面记录的是一份 内存地址, 类似 0x10000001 之类的,当你使用 obj2 = obj1 的时候,相当于把 内存地址 给了obj2,所以 obj1 obj2 其实指向的是同一 内存地址 ,也就是相同的内容,当你将 obj2 = {a : 222} 的时候, {a:222}也会存放到某一段 内存中, 并把内存地址给到 obj2 ,因此 obj2obj1 就不再指向同一个内存地址了。

看看下面的案例:

let obj1 = {
    a: 1,
    b: 2,
}
let obj2 = obj1;
obj2 = {
    a: 11,
    b: 22,
}
console.log(obj1)    // { a: 1, b: 2 }
console.log(obj2);    // { a: 11, b: 22 }

obj2 = obj1 ;
obj2.a = 111;
// 修改 obj2.a ,其实修改的也是 obj1.a 
console.log(obj1);    // { a: 111, b: 2 }

你对引用可能有误解,举例子:

如果说A是引用类型,那么执行B=A后,如果对A进行了修改,比如:

A.xxx=newVal

那么,B.xxx也会改变,反之也是。

不过,如果你执行了:

A=新的引用

那么,对B就没有影响了,反之也是。

总结:引用就是相当于A和B指向同一个对象,通过A或B就可以修改这个对象的内容,可是,比如B修改指向新的对象了,那么A依旧指向原来的对象,当然两个可以是不同的。

你这个属于误用了吧。fn2已经在你的修改下 fn2 = () => console.log(222),被重新定义了,那么就等于新开辟了内存空间去定义fn2了。当然fn2和fn1不一样了。

如同:

const a = {'a': 1, 'b': 2}
let b = a
b['c'] = 4

console.log(b)
// {a: 1, b: 2, c: 4}
console.log(a)
// {a: 1, b: 2, c: 4}

// 这里b被重新赋值,内存id与a的已经不同了
b = {'d': 5}
console.log(b)
// {d: 5}
console.log(a)
// {a: 1, b: 2, c: 4}

js 在 import、export 出来之前只有值传递,没有引用传递。

你对引用传递有误解,真正的引用传递:

function c(a) {
    a = {v:2};
}
let a = {v:1};
c(a);
console.log(a);
// 如果是引用传递,应该输出 {v:2}

引用传递代表传递的内容是变量的地址,等于给变量一个别名,给别名赋值、原变量也会变化。
目前 js 中应该只有 import、export 才有这种应用。

let a = {v:1};
setTimeout(() => {a = {v:2}}, 1000);
export {a};
import {a} from './a.js';

console.log(a);
// {v:1};

setTimeout(() => console.log(a), 1000);
// {v:2}

fn2 已经改了另外的指向了 肯定和第一个不同了啊

或者有什么方式的赋值,能体现出来函数是引用传递的?
const f = () => 1
f.a = 2
const g = f
g.a = 3
console.log(f.a, g.a) // 3 3
新手上路,请多包涵

// pointerFn1: () => console.log(111)
// pointerFn2: () => console.log(222)

const fn1 = pointerFn1
// 这里的赋值只是改变 fn1、fn2 的内存地址(指针)指向,并没有改变指向的值里的内容。
let fn2 = fn1 // 等价于 fn2 = pointerFn1
fn2 = pointerFn2

fn1() // 111
fn2() // 222

新手上路,请多包涵

fn2 = () => console.log(222)
这行代码删除就能完美体现应用传递

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题