简体   繁体   中英

Javascript: Object have keys, but Object.keys returns empty

在此处输入图片说明

I have an object, as you can see in picture, when i console.log() it, in first row it says course is an array of 0 length. when i expand it, it says length is 1, when i do course.length it says 0. Object.keys(course).length also says 0.

What i do in my app is, I have a listview. each item on listview is expandable. each item is a container, and each container have courses. i got containers and courses from remote server. everything was working perfectly. now i'm trying to load data from local database. it's not working anymore...

Please see my simplified code :

 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) }); }

I read lots of questions on stackoverflow, many articles, but no successs :( Object.keys(Obj).length Obj.length all returns 0. Some says because Obj.length will only show enumerable properties. i tried adding enumerable properties to object with Object.defineproperty but no changes.

any solutions? any help is highly appreciated.

The whole code (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);

There are 3 factors that can cause the general behavior you describe. In your case, I think it's the first:

  1. When you invoke console.log(x) , the Chrome console will show a summary of the object x at the time. However, when you expand the object, the value is obtained again . The detailed object you see may have changed since the call to console.log() , and changes will appear in the detail .

  2. Properties may belong to an object's prototype (as opposed to "own" properties):

     > x = {a:1} { a: 1 } > y = Object.create(x) > ya 1 > y {} > Object.keys(y) []
  3. Properties may be non-enumerable, and won't show up in key listings. length is a non-enumerable property.

As you said, Object.keys refers to enumerable properties. The "length" property of an array (which is also an object) is simply not enumerable.

Try this,

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM