js对象属性不能调用自己的方法吗?

我想初始化一个对象如下:

let obj = {
    i: this.getI(),
    getI: function(){
        return 1
    }
}

这样写的话就会说getI未被定义,我想知道为什么?如果说一个对象的属性想用函数获得初始化的值的话是不是就只能把函数定义在外面了?

阅读 2.6k
6 个回答

第一个问题

json对象不能直接调用自身的key来将val赋值给自身的其他key, 这个和加载顺序有关, 需要整个obj初始化完毕后才能调用, 如下会报错

let obj = {
  a: 0,
  b: obj.a // Cannot access 'obj' before initialization
}

你上面的geiI也是同理, 当程序读取到i: obj.getI()这句话时, 会检查obj对象是否已经完成初始化, 显然这个时候还没有完成, 所以肯定会报错, 除非这样子写

<script>
  const getI = () => 1;

  let obj = {
  i: getI(),
    getI: function() {
        return 1
    }
  }

  console.log(obj.i); // 1
</script>

确保你在将getI()赋值给i之前getI()已经被定义过了, 运行则通过

第二个问题: 如果说一个对象的属性想用函数获得初始化的值的话是不是就只能把函数定义在外面了?

首先要理解, 要给一个对象的属性赋值, 那么这个值必须是实际存在的, 如数值123, 或者是一个字符串, 甚至是值undefined也可以, js中基本数据类型的值都能赋值, 但是你不能赋值一个不存在的函数或对象, 当你写了 i: this.getI(), 程序会先执行右边的this.getI()来返回一个实际的值, 找不到就会报错

第三个问题: 那如果说想用这个对象自己的方法来初始化这个这个对象的属性是做不到的吗?

可以做到, 但是要保证想要赋给属性的值在赋值之前必须存在
打个比方 : 往容器装水
那么, 做这个事情就必须存在三个要素, 缺一不可

  1. 装水的容器
  2. 要装的水
  3. 装水行为

如下代码

// 容器对象
const container = {
    // 装水行为
    waterFilling: function() {
        // 要装的水是100ml
        container.waterVolume = 100
    }
}

在这段代码中将三个必要条件定义好之后才能进行操作

console.log(container.waterVolume); // 这个时候还没有装水, 所以是undefined

container.waterFilling(); // 执行装水

console.log(container.waterVolume); // 100

这样就可以实现了对象自身方法container.waterFilling()来初始化自身属性container.waterVolume

除此之外, container 的定义还可以这样写

const container = {
    num: 100,
    waterFilling: function() {
        container.waterVolume = container.num
    }
}

console.log 结果同上

但是, 如下写法就会报错

// 容器对象
const container = {

    // 预装水量
    num: 100,

    // 报错, 因为在这个时候容器根本不存在!
    waterVolume: container.num

}

在定义时将自身其他属性作为值num, 赋值给另一个属性waterVolume就不行
如果一定要这么做, 可以在container定义好之后再赋值

const container = {
    num: 100
}
container.waterVolume = container.num;
console.log(container.waterVolume) // 100

但是将一个函数作为值赋值给属性, 在函数里不管这个值是否存在, 都能正常运行
这是因为, 你只是定义了一个函数, 并没有去执行他

const container = {
    waterFilling: function() {
        container.waterVolume = num
    }
}

// console.log(num); // error : num is not defined
container.waterFilling(); // error : num is not defined
let obj = {
  - i: this.getI(),
  + i: function () {
        return this.getI();
    },
    getI: function(){
        return 1
    }
}

定义这个对象时,this 指向全局对象(浏览器里是 window), window 上没有 getI 这个方法,当然是未定义啦。你可以用 class 或者用一个立即执行函数

class Obj {
    getI = function() {
        return 1
    }
    i = this.getI();
}

let obj = new Obj();
let obj = {
    i: (() => {
        return 1 + 2;
    })(),
    getI: () => {},
}

就拿你的这个数据结构来说,声明obj并给他赋值的时候,肯定要先确定值,i的值是什么,this.getI(),是一个代码语句,那么会运行这个代码,然后this找到什么了,在当前环境下找到的this是什么要看你的运行环境,但肯定不是obj,那把this.getI()换成obj.getI()行不行,也不行,因为obj还未声明,换成var声明,就是已声明未赋值,也不能这样用

因为给obj初始化赋值调用this.getI()时,this不是指向obj。
this的指向与函数的调用方式有关,一般情况下谁调用这个函数,函数中的this就指向谁,你的obj定义在全局环境下,可以把全局看作一个全局函数内部,此时this指向的是全局对象window,在给obj赋值时,会去执行this.getI(),会去查找全局对象下的getI并调用,但是全局对象下并没有getI所以会报错。

使用 getter

let obj = {
    get i () {
        return this.getI()
    },
    getI: function(){
        return 1
    }
}
console.log(obj.i) // 输出 1
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题