Javascript: у объекта есть ключи, но Object.keys возвращает пустой

#javascript #arrays #object

#javascript #массивы #объект

Вопрос:

введите описание изображения здесь

У меня есть объект, как вы можете видеть на картинке, когда я его console.log() , в первой строке он говорит, что course — это массив длиной 0. когда я разворачиваю его, он говорит, что длина равна 1, когда я делаю курс.длина говорит 0. Object.keys(курс).длина также указывает 0.

Что я делаю в своем приложении, так это то, что у меня есть listview. каждый элемент в listview можно расширять. каждый элемент является контейнером, и в каждом контейнере есть курсы. я получил контейнеры и курсы с удаленного сервера. все работало отлично. теперь я пытаюсь загрузить данные из локальной базы данных. это больше не работает…

Пожалуйста, посмотрите мой упрощенный код :

 export default class Main extends Component{
  constructor(props) {
    super(props);
    this.state = {
      dataSource: new ListView.DataSource({
              rowHasChanged: (row1, row2) => row1 !== row2,
            })
    };
  }
  
  componentWillMount(){
    this.fetchData();
  }
  
  fetchData(){
    let data = fetch..... //// fetches data
    let dsource = {};
    
    for(let i=0; i < data.containers.length; i  ){
      let container = data.containers[i];
      dsource[i] = {
        containerId: containder.id,
        course: [],
      }
      for(let x=0; x < container.courses.length; x  ){
         let course = container.courses[x];
        dsource[i].course.push({
          courseId: course.id,
          courseName: course,name
        });
      }
     }
    
    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(dsource)
    });
    
  }  

Я прочитал много вопросов по stackoverflow, много статей, но безуспешно:( Object.keys(Obj).length Obj.length все возвращает 0.
Некоторые говорят, потому что Obj.length будет показывать только перечислимые свойства. я попытался добавить перечислимые свойства к объекту с помощью Object.defineproperty, но без изменений.

какие-либо решения? любая помощь приветствуется.

Весь код (react native) :

 "use strict";

import React, {Component, PropTypes} from 'react';
import {
  ActivityIndicator,
  ListView,
  StyleSheet,
  Text,
  View,
  Image,
  NetInfo,
  AlertIOS,
  TouchableOpacity,
  ScrollView,
  Dimensions,
} from 'react-native';

let SQLite = require('react-native-sqlite-storage');
let Loading = require("./Loading");
let Accordion = require('react-native-accordion');
let DeviceInfo = require('react-native-device-info');
import Icon from 'react-native-vector-icons/Ionicons';
import { Actions } from 'react-native-router-flux';
import I18n from 'react-native-i18n';
import translations from './translations';
I18n.fallbacks = true;
let LOADING = {};
import CodePush from "react-native-code-push";
let { width, height } = Dimensions.get('window');
let db = SQLite.openDatabase({name : "oc.db", location: 'default'});

export default class Courses extends Component {
  constructor(props) {
        super(props);
        this.state = {
            isLoading: false,
            dataSource: new ListView.DataSource({
              rowHasChanged: (row1, row2) => row1 !== row2,
            }),
            isConnected: true,
            dataLoaded: 0,
            restartAllowed: true
        };
    }

    toggleAllowRestart() {
      this.state.restartAllowed
        ? CodePush.disallowRestart()
        : CodePush.allowRestart();

      this.setState({ restartAllowed: !this.state.restartAllowed });
    }

    sync() {
    CodePush.sync(
      {
        installMode: CodePush.InstallMode.IMMEDIATE,
        updateDialog: false
      },
    );
  }

  componentWillMount() {
    NetInfo.isConnected.fetch().then(isConnected => {
      this.setState({
        isConnected: isConnected
      });
    });

    NetInfo.isConnected.addEventListener(
      'change',
      isConnected => {
        this.setState({
          isConnected: isConnected
        });
      }
    );

    this.fetchData();
    this.sync();
  }
    componentWillReceiveProps() {
      this.fetchData();
      this.setState({
        keyForCourse: Date()
      });
      if(this.props.goto == 'register'){
        Actions.register({type: 'reset'});
      }
    }

  fetchData() {
    console.log('Courses: fetchData running');
    if(this.state.isConnected == 'wifi' || this.state.isConnected == 'cell' || this.state.isConnected == 'true' || this.state.isConnected){
        this.setState({
          isLoading: true,
        });
        db.transaction((tx) => {
            tx.executeSql("SELECT * FROM users WHERE active=?",['yes'], (tx, results) => {
                let len = results.rows.length;
                let row = results.rows.item(0);
                let userName = row.userName;
                let userMail = row.userMail;
                let userId = row.userId;
                ///// Getting courses list
                db.transaction((tx) => {
                      tx.executeSql("SELECT * FROM containersC WHERE userId=?",[userId], (tx, results) => {
                          let dsource = {};
                          let len = results.rows.length;
                          if(len > 0){
                            for(let ind = 0; ind < len; ind   ){
                              let cntr = results.rows.item(ind);
                              dsource[ind] = {
                                  nid: cntr.nid,
                                title: cntr.title,
                                course: [],
                                courses: {},
                              };
                              //// Get courses for each container
                              db.transaction((tx) => {
                                    tx.executeSql("SELECT * FROM courses WHERE userId=? AND container_nid=?",[userId, cntr.nid], (tx, results) => {
                                        let lenc = results.rows.length;
                                        if(lenc > 0){
                                            for(var j=0; j < lenc; j  ){
                                              let crs = results.rows.item(j);
                                              console.log('Course:', crs);
                                              dsource[ind].course.push({
                                                course_id: crs.course_id,
                                                title: crs.title,
                                                cost: crs.cost,
                                                status: crs.status,
                                                period: crs.period // .time_sys
                                              });

                                              dsource[ind].courses[j] = {
                                                course_id: crs.course_id,
                                                title: crs.title,
                                                cost: crs.cost,
                                                status: crs.status,
                                                period: crs.period // .time_sys
                                              };
                                            }
                                            dsource[ind].total = lenc;
                                          }
                                        }, function(){
                                        console.log('Courses: Something went wrong Line 142');
                                      });
                                  });
                              //// End getting courses for containers
                            }
                            this.setState({
                              dataSource: this.state.dataSource.cloneWithRows(dsource),
                              isLoading: false,
                              dataLoaded: len
                            });
                          }
                        }, (err)=>{
                          console.log('Courses: Something went wrong', err);
                        });
                    }
                );
                //// End getting courses list
              }, function(){
                console.log('Courses: Unable to select users from database');
              });
          });
      } else {
        AlertIOS.alert(
          I18n.t("no_connection_title"),
          I18n.t("no_connection_desc")
        );
      }
    }

  selectRow(d, n) {
    Actions.cdetails({cid: d, tit: n});
    //Actions.rdetails({cid: d, tit: n});
  }

  renderRow(data) {
    let header = (
      <View style={{ backgroundColor: '#fff', margin: 7, marginBottom: 0 }}>
          <View style={styles.rowContainer}>
            <View  style={styles.textContainer}>
              <Icon name="ios-arrow-up" color="#00a2dd" size={30}></Icon>
              <Text style={styles.title}>{data.title}</Text>
            </View>
          </View>
    </View>
    );
    let headerOpen = (
      <View style={{ backgroundColor: '#fff', margin: 7, marginBottom: 0 }}>
          <View style={styles.rowContainer}>
            <View  style={styles.textContainer}>
              <Icon name="ios-arrow-down" color="#00a2dd" size={30}></Icon>
              <Text style={styles.title}>{data.title}</Text>
            </View>
          </View>
          <View style={styles.separator}></View>
    </View>
    );
///////////
    let cid = [];
    let content = [];
    let cll = data.total;
    console.log('Data to render :', data);
    console.log('Courses to render :', data.course);
    for(let x=0; x < cll; x  ){
      cid[x] = data.course[x].course_id;
      let courseCost;
      switch(data.course[x].cost){
        case 0:
        courseCost = I18n.t("course_fee_free");
        break;
        case 1:
        courseCost = data.course[x].cost;
        break;
      }
      content.push(
        <TouchableOpacity key={cid[x]} onPress={()=>{this.selectRow(data.course[x].course_id, data.course[x].title)}} >
        <View style={[styles.cardContainer, {marginBottom: 5}, x == 0 ? { paddingTop: 6, } : {}, x == (cll 1) ? { marginBottom: 3} : {}]} key={cid[x]} >
          <View style={styles.card}>
            <View resizeMode="cover" style={styles.cardTitleContainer}>
              <Text style={styles.cardTitle}>{data.course[x].title}</Text>
            </View>
            <View
            style={{
                padding : 15,
              }}
              >
              <Text style={styles.cardContent}>
                <Icon name="ios-calendar" color="#00a2dd" size={10}> {data.course[x].period}</Icon>{'n'}
                <Icon name="ios-pricetag" color="#00a2dd" size={10}> {courseCost}</Icon>
              </Text>
            </View>
          </View>
        </View>
        </TouchableOpacity>
      );
    }
    let clist = (
      <ScrollView style={styles.scrollView}>
      <View style={{
        padding: 6,
        paddingBottom: 0,
        borderTopColor: '#fff',
        backgroundColor: '#fff',
        margin: 7,
        marginTop: 0,
      }}>{content}</View>
      </ScrollView>
    );
////////////
  return (
    <Accordion
      header={header}
      headerOpen={headerOpen}
      content={clist}
      easing="easeOutCubic"
      underlayColor="#ebebeb"
    />
  );
  }

  render() {
    let content= null;
    if(this.state.isLoading){
      content = <Loading/>;
    } else {
      if(this.state.dataLoaded < 1){
      content = <View style={styles.errorContainer}>
     <View style={styles.error}>
     <Text style={styles.Errortext}>
      {I18n.t("courses_no_course_available")}
      </Text>
      </View>
     </View>;
      } else {
      content = <View style={{
        flex: 1
      }}>
      <ListView
        dataSource={this.state.dataSource}
        renderRow={this.renderRow.bind(this)}
      />
      </View>;
    }
    }

    return (
      <View style={styles.container}>
      {content}
      </View>
    );
  }
}

let styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "white",
    flexDirection: "column",
    justifyContent: "center",
    backgroundColor: '#e4e7ea',
  },
  separator: {
    height: 1,
    backgroundColor: "#d0d1d3",
  },
  scrollSpinner: {
    marginVertical: 20,
  },
  cardContainer:{
    flex: 1,
    alignItems: 'stretch',
    paddingLeft: 6,
    paddingRight: 6,
    borderColor: '#d0d1d3',
    borderWidth: 1,
    borderRadius: 5
  },

  card:{
    flex: 1,
    backgroundColor: '#ffffff',
    borderRadius: 2,
    borderColor: '#ffffff',
    borderWidth: 1,
    /*shadowColor: 'rgba(0, 0, 0, 0.12)',
    shadowOpacity: 0.8,
    shadowRadius: 2,
    shadowOffset: {
      height: 1,
      width: 2,
    },
    */
  },
  cardTitleContainer:{
    flex: 1,
    height: 35,
  },
  cardTitle:{
    position: 'absolute',
    top: 5,
    left: 5,
    backgroundColor: 'transparent',
    padding: 10,
    fontSize: 12,
    color: '#4c4b4b',
    fontWeight: 'bold',
  },
  rowContainer: {
    flexDirection: 'column',
    padding: 5,
  },
  textContainer: {
    flexDirection: 'row',
    flex: 1,
    padding: 5
  },
  title: {
    paddingTop: 7,
    paddingLeft: 5,
    color: '#00a2dd'
  },
  errorContainer: {
    flex: 1,
    flexDirection: "column",
    backgroundColor: '#e4e7ea',
    alignItems: 'center',
  },
  error: {
    marginTop: 75,
    width: width -150,
    height: 100,
    borderRadius: 15,
    backgroundColor: '#ecebeb',
    alignItems: 'center',
    justifyContent: 'center',
  },
  Errortext: {
    color: '#757575'
  },
});

Courses = CodePush(Courses);  

Комментарии:

1. Что вам явно нужно, покажите нам, что у вас не так в вашем коде?

2. Вы пробовали Object.keys(array) затем получить ключ по индексу? jsbin.com/huqojefiti/1/edit также поможет еще немного кода

3. course это массив длиной 1, а ваш объект находится в позиции 0

4. Я обновил вопрос целым кодом. пожалуйста, посмотрите на.

Ответ №1:

Есть 3 фактора, которые могут вызвать общее поведение, которое вы описываете. В вашем случае, я думаю, это первое:

  1. При вызове console.log(x) консоль Chrome покажет сводную информацию об объекте x в данный момент. Однако, когда вы разворачиваете объект, значение получается снова. Подробный объект, который вы видите, возможно, изменился с момента вызова console.log() , и изменения появятся в деталях.

  2. Свойства могут принадлежать прототипу объекта (в отличие от «собственных» свойств):

     > x = {a:1}
    { a: 1 }
    > y = Object.create(x)
    > y.a
    1
    > y
    {}
    > Object.keys(y)
    []
      
  3. Свойства могут быть неисчислимыми и не будут отображаться в списках ключей. length является неисчислимым свойством.

Комментарии:

1. таким образом, возможно, что мой код не выполняется, следовательно, и перед его извлечением и помещением всех данных в массив, он пытается показать содержимое и его длину. верно? я попытаюсь использовать async / await, чтобы посмотреть, что произойдет. спасибо за ваш ответ

Ответ №2:

Попробуйте это,

  const keys =[];  
    const person = {
    name : 'Jobelle',
    age :22,
    mob :8547391599
    }
    
    Object.getOwnPropertyNames(tempObj).forEach(prop => {
              keys.push(prop);
            });
  

Ответ №3:

Как вы сказали, Object.keys относится к перечислимым свойствам. Свойство «длина» массива (который также является объектом) просто не поддается перечислению.

Комментарии:

1. Итак, что вы предлагаете? как я могу узнать, сколько элементов находится внутри массива или объекта?

2. Я не думаю, что OP регистрирует массив, хотя его формулировку можно понять таким образом. Регистрируется объект, свойство которого course показывает пустой массив, но при использовании показывает полный массив. Примечание : downvote не от меня.

3. Прежде всего, объясните свои отрицательные голоса, чтобы мы все могли учиться! Может быть, я просто что-то неправильно понял в отношении вопроса, но то, что я сказал, в целом правильно. @Ataomega: Используется length для определения количества элементов в массиве . Используется Object.keys для определения количества (перечислимых) свойств в объекте . По крайней мере, так я это делаю.

4. @frontend_dev спасибо за ваш комментарий. поскольку длина возвращала ноль, я попробовал Object.keys().length , который также вернул ноль

5. @frontend_dev во время тестирования я попробовал оба варианта. я добавил один курс и курсы, один массив и другой один объект. попробовал длину и Object.keys. длина для обоих из них, ни одна не работает должным образом.