最优雅的方式来初始化对象的缺失成员,同时创建对新成员的引用

时间:2018-03-07 19:39:08

标签: javascript ecmascript-6 javascript-objects lazy-initialization

请求最优雅的解决方案。我们都处理可以在其整个生命周期中逐步构建的对象。传递对象引用是处理对象最有用的方法,因为突变会影响原始而不仅仅是副本。

例如:

const bigObject = fetchBigObjectFromStorage()
let myMem = bigObject.member || {}

如果member中存在bigObjectmyMem会获得对它的引用。如果没有,它只接收对新空对象的引用。所以这有不可预测的结果:

myMem.value = 30

没有错误。 myMem.value现在是30.但是价值最终会在我们真正想要的地方结束吗?

console.log(bigObject.member.value)

这显示30或提供TypeError,因为bigObject.member未定义,具体取决于bigObject.member是否已存在。

为了避免错误,我们可以将新值重新放回bigObject,每次都将其重新放回去,我们需要明确指定它:

bigObject.member = myMem

这很乱。

因此,我们可以预先考虑bigObject.member不存在的可能性,测试它,并在我们开始尝试传递对它的引用之前插入它,甚至用空值初始化所需的成员。所以我们有这个代码:

const bigObject = fetchBigObjectFromStorage()
if (!bigObject.hasOwnProperty("member")) bigObject.member = {value: null}
let myMem = bigObject.member
myMem.value = 30
console.log(bigObject.member.value)

...我们每次都没有出现任何错误,显示错误和可靠的行为(好吧,差不多...... if中的几个测试可能会让它变得无懈可击)。但它像罪一样丑陋,而且代码太多而无法实现。我们可以像将if语句一样重构为一个小函数,使其成为通用成员初始化器,以及其他一些方法。我相信多年来我们大多数人都尝试过很多技术。但是,汇集学习人群的最优雅,最受青睐的解决方案是什么?任何聪明的小技巧?

3 个答案:

答案 0 :(得分:2)

您可以使用条件运算符缩短if语句:

const myMem = bigObject.hasOwnProperty("member") 
  ? bigObject.member
  : (bigObject.member = {value: null});

如果真实性检查对您来说足够了,那么您可以使用短路逻辑运算符进一步简化:

const myMem = bigObject.member || (bigObject.member = {value: null});

ES6解构可能是最优雅的方式,默认情况下使用默认的initaliser,它会隐式测试undefined

const { member: myMem = (bigObject.member = {value: null}) } = bigObject;

答案 1 :(得分:1)

怎么样

<property name="remarksReporting" value="true"/>

其中const bigObject = {...defaults, ...fetchBigObjectFromStorage()} 类似于:

defaults

这样,您的对象始终具有所有预期的字段。

答案 2 :(得分:0)

function LocationClass()
{
     this.map = null;
     this.divLocation = null;

this.Initialize = function()
{
    this.divLocation = document.getElementById("Location");

    this.map = new google.maps.Map(document.getElementById('Map'), 
    {
      center: { lat: -34.397, lng: 150.644 },
      zoom: 10,
      fullscreenControl: false,
      mapTypeControl: false,
      scrollwheel: false,
      zoomControl: false,
      streetViewControl: false
    });

    console.log(this.divLocation);
}

this.UpdateMap = function(aLong, aLat)
{
    this.map.panTo({lat: aLat, lng: aLong});
}

this.GetLocation = function()
{
    if (navigator.geolocation) 
    {
        navigator.geolocation.getCurrentPosition(this.ShowPosition, this.ShowError);
    } 
    else 
    {
        this.divLocation.innerHTML = "Geolocation is not supported by this browser.";
    }
}

this.ShowPosition = function(aPosition)
{
    this.divLocation.innerHTML = "<strong>Latitude:</strong> " + aPosition.coords.latitude +
    "<br><strong>Longitude:</strong> " + aPosition.coords.longitude;
    var geocoder = new google.maps.Geocoder();
    var location = new google.maps.LatLng(aPosition.coords.latitude, aPosition.coords.longitude);       
    geocoder.geocode({ 'latLng': location }, function (results, status) 
    {
        if (status == google.maps.GeocoderStatus.OK)
        {           
            //var add = results[0].formatted_address;
            let city = "";
            let components = results[0].address_components;
            for (var component = 0 ; component < components.length; component++)
            {
                if (components[component].types[0] == "postal_town")
                {
                    city = components[component].long_name;
                }
            }
            this.divLocation.innerHTML += "<br><strong>City:</strong> " + city + "</strong>";
        }
    });

    weatherApp.GetWeatherByCoords(aPosition.coords.latitude, aPosition.coords.longitude);
}

this.ShowError = function(aError)
{
    switch(aError.code) 
    {
        case aError.PERMISSION_DENIED:
        this.divLocation.innerHTML = "User denied the request for Geolocation."
            break;
        case aError.POSITION_UNAVAILABLE:
        this.divLocation.innerHTML = "Location information is unavailable."
            break;
        case aError.TIMEOUT:
        this.divLocation.innerHTML = "The request to get user location timed out."
            break;
        case aError.UNKNOWN_ERROR:
        this.divLocation.innerHTML = "An unknown error occurred."
            break;
    }
}
}

我认为这可能是其中一招