JS容易理解错误的地方

原创
2018/12/19 11:36
阅读数 107

在这端代码执行的末尾,你会不会hi变量回事函数中的hi了?你会不会认为这不是按引用传递了? 对值传递和引用传递产生质疑了?

1   var hi = {};

2   function sayHello(hi) {
        
        // 这样来给hi赋值,声明的hi变量不会有任何变化,在函数外侧hi还是那个{}
        hi = {
            a: 'b'
        };    
        
        console.log('in function hi : ' + hi.a);
        alert(hi.a);
    }
    sayHello(hi);
    console.log('out function: ' + hi.a);  // 此时函数外的hi还是{}

辨析:
   1 是实参hi   
   2 是形参hi
虽然名字同名但同名不是同一个变量,是两个不同的变量,虽然同名同名,但存放的内存位置不同。
同名会迷惑你。
实参hi是一个对象,在sayHello被调用时,会将引用赋值给形参hi,在函数内部我们将一个新对象赋值给形参hi,这时形参hi的引用发生了变化,指向了新的对象,但实参hi的引用并没有发生变化,所以函数调用后实参hi还是那个实参hi,这个函数值传递形式还是按引用传递,只不过我们在函数内部改变了形参hi的引用指向。如果不改变引用指向,可以在函数中修改实参hi的属性值。
不要被表象所迷惑。
   

这个问题是我在阅读seajs的源码发现的困惑,为什么这样写,在另一个模块中require是不能获取到暴露出的对象:

seajsUtil.js

define(function (require, exports, module) {

    exports = {
        a: 'meng',
        b: 'miao'
    };
    
});


seajsDemo.js

define(function (require, exports, module) {

    var seaUtil = require('./seaUtil');

    console.log(seaUtil.a);   // 报a未定义
});

理解了以上的困惑,就告诉我们正确的暴露对象的方法是:

// 这样才是使用exports暴露变量和属性的正确姿势,exports本身是一个空对象{},要在空对象上进行添加属性和函数
define(function (require, exports, module) {

    exports.a = 'meng';
    exports.b = 'miao';
    exports.sayHello = function(){
        alert('hi');
    }
});

// 直接return对象或者属性,这样就回避了exports属性暴露,使用return直接暴露,使用return可以暴露各种类型的值。
// 是的适合,使用起来感觉比exports更便捷。暴露模块内容的方法可以是情况进行选择。
define(function (require, exports, module) {

   return {a: 'meng', b: 'miao'};
});


//这是seajs的暴露模块属性的代码:
    /**
     * 如果构造函数factory不返回,则exports取mod.exports变量作为返回对象。也即是seajs模块的的交互,句柄持有的对 
     * 象,要么是factory的return对象,要么是exports对外发布的对象。
     * factory被赋予的exports是一个对象,所以通过exports暴露的就是一个对象。
     */
    var exports = isFunction(factory) ?
      factory(require, mod.exports = {}, mod) :
      factory

    if (exports === undefined) {
      exports = mod.exports
    }

    // Reduce memory leak
    delete mod.factory

    mod.exports = exports
    mod.status = STATUS.EXECUTED

    // Emit `exec` event
    emit("exec", mod)

    return exports


  /**
   * require返回mod.exports,供其他模块接收使用.
   * require返回的exports变量,模块要给exports变量赋值
   */
  seajs.require = function (id) {
    var mod = Module.get(Module.resolve(id))
    if (mod.status < STATUS.EXECUTING) {
      mod.onload()
      mod.exec()
    }
    return mod.exports
  }

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部