创建JavaScript environment对象时,如何访问同一对象内已定义属性?
解决JavaScript对象字面量中访问自身属性的问题
我想要创建如下的environment对象:
export const environment = { production: false, hmr : false, api: { auth: { protocol: 'http', host: 'localhost', port: '8083', api_path: 'api', version: { path: 'v', major: 1, minor: 0, patch: 0, }, url: this.api.auth.protocol + '://' + this.api.auth.host + ':' + this.api.auth.port, controllers: { auth: { service_name: 'auth', base_url: this.api.auth.url + '/' + this.api.auth.controllers.auth.service_name + '/' + this.api.auth.api_path + '/' + this.api.auth.version.path + '/' + this.api.auth.version.major + '.' + this.api.auth.version.minor + '.' + this.api.auth.version.patch + '/', refresh_token_url: this.api.auth.controllers.auth.base_url + '/refresh_token', login_url: this.api.auth.controllers.auth.base_url + '/login', logout_url: this.api.auth.controllers.auth.base_url + '/logout' } } } } };我希望在同一对象中访问已赋值的属性,例如在
api.auth.url中通过this.api.auth.protocol访问api.auth.protocol,拼接出http://localhost:8083这类URL。但当前写法无法访问,编译后报错:“Uncaught TypeError: Cannot read property 'api' of undefined”。我是开发新手,请问如何解决该问题?
为啥你的代码会报错?
在你写的这种对象字面量({ ... }结构)里,this并不会指向正在创建的environment对象哦!它的指向取决于当前代码的运行上下文(比如浏览器里默认是window,严格模式下是undefined),自然找不到this.api,所以才会报错。
几种适合新手的解决方法
方法1:先创建基础对象,再补全依赖属性
先把不需要依赖其他属性的部分写好,再逐步添加那些需要拼接的属性,这样就能直接访问已经存在的属性了:
export const environment = { production: false, hmr : false, api: { auth: { protocol: 'http', host: 'localhost', port: '8083', api_path: 'api', version: { path: 'v', major: 1, minor: 0, patch: 0, }, } } }; // 补全url属性,用模板字符串拼接更清爽 environment.api.auth.url = `${environment.api.auth.protocol}://${environment.api.auth.host}:${environment.api.auth.port}`; // 补全控制器相关属性 environment.api.auth.controllers = { auth: { service_name: 'auth', base_url: `${environment.api.auth.url}/${environment.api.auth.controllers.auth.service_name}/${environment.api.auth.api_path}/${environment.api.auth.version.path}/${environment.api.auth.version.major}.${environment.api.auth.version.minor}.${environment.api.auth.version.patch}/`, refresh_token_url: `${environment.api.auth.controllers.auth.base_url}/refresh_token`, login_url: `${environment.api.auth.controllers.auth.base_url}/login`, logout_url: `${environment.api.auth.controllers.auth.base_url}/logout` } };
方法2:提前定义变量,再构建对象
把需要复用的属性先提取成单独变量,最后再把这些变量组装成对象,这种方式逻辑最清晰,完全不用纠结this的指向问题,新手友好度拉满:
// 先把所有基础配置拆成变量 const protocol = 'http'; const host = 'localhost'; const port = '8083'; const apiPath = 'api'; const version = { path: 'v', major: 1, minor: 0, patch: 0, }; const serviceName = 'auth'; // 提前计算好需要拼接的URL const authBaseUrl = `${protocol}://${host}:${port}`; const authControllerBaseUrl = `${authBaseUrl}/${serviceName}/${apiPath}/${version.path}/${version.major}.${version.minor}.${version.patch}/`; // 最后组装成完整对象 export const environment = { production: false, hmr : false, api: { auth: { protocol, host, port, api_path: apiPath, version, url: authBaseUrl, controllers: { auth: { service_name: serviceName, base_url: authControllerBaseUrl, refresh_token_url: `${authControllerBaseUrl}/refresh_token`, login_url: `${authControllerBaseUrl}/login`, logout_url: `${authControllerBaseUrl}/logout` } } } } };
我个人最推荐这种写法,后续修改配置或者排查问题都特别方便。
方法3:用getter函数动态计算属性
如果想把所有代码放在一个对象字面量里,可以用get关键字定义getter属性,每次访问这个属性时会自动计算结果:
export const environment = { production: false, hmr : false, api: { auth: { protocol: 'http', host: 'localhost', port: '8083', api_path: 'api', version: { path: 'v', major: 1, minor: 0, patch: 0, }, // 用getter定义url,这里的this指向api.auth get url() { return `${this.protocol}://${this.host}:${this.port}`; }, controllers: { auth: { service_name: 'auth', // 这里的this指向controllers.auth,需要手动关联上层对象 get base_url() { const auth = environment.api.auth; return `${auth.url}/${this.service_name}/${auth.api_path}/${auth.version.path}/${auth.version.major}.${auth.version.minor}.${auth.version.patch}/`; }, get refresh_token_url() { return `${this.base_url}/refresh_token`; }, get login_url() { return `${this.base_url}/login`; }, get logout_url() { return `${this.base_url}/logout`; } } } } } };
这种方法的好处是,如果后续修改了protocol或host,url会自动更新,但要注意每次访问getter属性都会重新计算哦。
内容的提问来源于stack exchange,提问作者Asaduzzaman Noor
相关产品推荐
相关产品推荐

