关于闭包或者是作用域的问题

function student () {
    var name = 'xxx';
    var getName = function () {
        return name
    }
    var setName = function (newName) {
        name = newName;
    }
    return {
        getName: getName,
        setName: setName,
        name: name
    }
}
var studentA = student();
console.log(studentA.getName())
studentA.setName("aaa");
console.log(studentA.getName())
console.log(studentA.name);

为啥输出了是

clipboard.png

按道理不是名字已经变成aaa了吗?


更具指导是要在get和set里面都加上this.name就可以了,请问是为什么,我之前写的两个name不是同一个作用域?


我知道了,我把闭包分配的空间和return的空间混淆在一起了,所以没用this是对闭包的 空间的修改然后用this是对这个return的对象的修改

阅读 2.9k
4 个回答

首先,你的function里面返回来的是一个新的object对象,然后name是直接拷贝你已经在楼上几个得知了。
接着我们看一下this的指向:

function student () {
  var name = 'xxx';
  var getName = function () {
    return name
  };

  var setName = function (newName) {
    name = newName;
    
    return this;
  };

  return {
    getName: getName,
    setName: setName,
    name: name,
  };
}
var studentA = student();
var whoAmI = studentA.setName("aaa");

console.log(whoAmI); // {getName: ƒ, setName: ƒ, name: "xxx"}

恩恩,this指向了这个return的object对象,为什么呢?因为这个object其实是引用传递给了studentA,studentA调用了这个方法,this自然就指向了studentA。

为了证明这点,我们不从studentA调用,我们直接在内部调用:

function student () {
  var name = 'xxx';
  var getName = function () {
    return name
  };

  var setName = function (newName) {
    name = newName;
    
    return this;
  };

  const whoAmI = setName("aaa");
  console.log(whoAmI); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}

  return {
    getName: getName,
    setName: setName,
    name: name,
  };
}
var studentA = student();

是的,独自调用setName,返回来的this就是指向window的(或者说任何没有指定作用域的函数声明都会指向window)。

所以你现在知道了,studentA调用getNamesetName,this都是指向这个object,那么改变这个object的name不就如楼上所说:

setName方法里写 this.name = newName。 就可以了。另外,getName 也要加上 this.name

如果能让你更加理解,你应该分解return

// 操作studentA就是在操作这个result
const result = {
    getName: getName,
    setName: setName,
    name: name,
};

return result;

name是原始类型,return的那一刻把name的值拷贝了了一份返回了,以后name的任何修改都影响不到你的返回值

setName方法里写 this.name = newName。 就可以了
另外,getName 也要加上 this.name

这里面其实有两个name属性:

  1. 一个是函数student的私有属性。
  2. 一个是执行student函数返回的对象。

getNamesetName方法设置的都是student的私有属性name
而最后一行输出的是返回对象的name属性。
由于name属性是值类型,所以不会像引用类型一样,出现一处引用改变,其他引用这个对象的变量也改变的情况。

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