Javascript:对象有键,但Object.keys返回空

时间:2016-10-11 15:21:45

标签: javascript arrays object

enter image description here

我有一个对象,正如你在图片中看到的那样,当我在console.log()它时,在第一行中它表示course是一个0长度的数组。当我扩展它时,它表示长度为1,当我做course.length它说0. Object.keys(course).length也说0。

我在我的应用中做的是,我有一个列表视图。 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)
    });
    
  }
&#13;
&#13;
&#13;

我读了很多关于stackoverflow的问题,很多文章,但没有成功:( Object.keys(Obj)。length Obj.length all返回0。 有些人说,因为Obj.length只会显示可枚举的属性。我尝试使用Object.defineproperty向对象添加可枚举属性,但没有更改。

任何解决方案?任何帮助都非常感谢。

整个代码(本机反应):

&#13;
&#13;
"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);
&#13;
&#13;
&#13;

3 个答案:

答案 0 :(得分:4)

有3个因素可能导致您描述的一般行为。在你的情况下,我认为它是第一个:

  1. 当您调用console.log(x)时,Chrome控制台会显示当时对象x的摘要。但是,展开对象时,会再次获取该值。您看到的详细对象自调用console.log()后可能已更改,更改将显示在详细信息中

  2. 属性可能属于对象的原型(而不是&#34;拥有&#34;属性):

    > x = {a:1}
    { a: 1 }
    > y = Object.create(x)
    > y.a
    1
    > y
    {}
    > Object.keys(y)
    []
    
  3. 属性可能是不可枚举的,并且不会显示在关键列表中。 length是一个不可枚举的属性。

答案 1 :(得分:0)

正如您所说,Object.keys指的是可枚举的属性。数组的“长度”属性(也是一个对象)根本不可枚举。

答案 2 :(得分:0)

试试这个,

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