JS技术问题:从大对象提取对象填充数组为何仅获最后一项?
问题:提取对象到数组时所有元素均重复最后一项的原因
问题场景
尝试从objPractice对象的books数组中提取格式为{isbn:'值', title:'值'}的对象,填充到array1数组,但最终数组内所有对象都和原数组的倒数第二项(因循环条件限制)完全相同。
原对象代码
let objPractice = { books: [ { isbn: "9781449325862", title: "Git Pocket Guide", subtitle: "A Working Introduction", author: "Richard E. Silverman", publish_date: "2020-06-04T08:48:39.000Z", publisher: "O'Reilly Media", pages: 234, description: "This pocket guide is the perfect on-the-job companion to Git, the distributed version control system. It provides a compact, readable introduction to Git for new users, as well as a reference to common commands and procedures for those of you with Git exp", website: "http://chimera.labs.oreilly.com/books/1230000000561/index.html" }, { isbn: "9781449331818", title: "Learning JavaScript Design Patterns", subtitle: "A JavaScript and jQuery Developer's Guide", author: "Addy Osmani", publish_date: "2020-06-04T09:11:40.000Z", publisher: "O'Reilly Media", pages: 254, description: "With Learning JavaScript Design Patterns, you'll learn how to write beautiful, structured, and maintainable JavaScript by applying classical and modern design patterns to the language. If you want to keep your code efficient, more manageable, and up-to-da", website: "http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/" }, { isbn: "9781449337711", title: "Designing Evolvable Web APIs with ASP.NET", subtitle: "Harnessing the Power of the Web", author: "Glenn Block et al.", publish_date: "2020-06-04T09:12:43.000Z", publisher: "O'Reilly Media", pages: 238, description: "Design and build Web APIs for a broad range of clients—including browsers and mobile devices—that can adapt to change over time. This practical, hands-on guide takes you through the theory and tools you need to build evolvable HTTP services with Microsoft", website: "http://chimera.labs.oreilly.com/books/1234000001708/index.html" }, { isbn: "9781449365035", title: "Speaking JavaScript", subtitle: "An In-Depth Guide for Programmers", author: "Axel Rauschmayer", publish_date: "2014-02-01T00:00:00.000Z", publisher: "O'Reilly Media", pages: 460, description: "Like it or not, JavaScript is everywhere these days-from browser to server to mobile-and now you, too, need to learn the language or dive deeper than you have. This concise book guides you into and through JavaScript, written by a veteran programmer who o", website: "http://speakingjs.com/" }, { isbn: "9781491904244", title: "You Don't Know JS", subtitle: "ES6 & Beyond", author: "Kyle Simpson", publish_date: "2015-12-27T00:00:00.000Z", publisher: "O'Reilly Media", pages: 278, description: "No matter how much experience you have with JavaScript, odds are you don’t fully understand the language. As part of the \"You Don’t Know JS\" series, this compact guide focuses on new features available in ECMAScript 6 (ES6), the latest version of the st", website: "https://github.com/getify/You-Dont-Know-JS/tree/master/es6%20&%20beyond" }, { isbn: "9781491950296", title: "Programming JavaScript Applications", subtitle: "Robust Web Architecture with Node, HTML5, and Modern JS Libraries", author: "Eric Elliott", publish_date: "2014-07-01T00:00:00.000Z", publisher: "O'Reilly Media", pages: 254, description: "Take advantage of JavaScript's power to build robust web-scale or enterprise applications that are easy to extend and maintain. By applying the design patterns outlined in this practical book, experienced JavaScript developers will learn how to write flex", website: "http://chimera.labs.oreilly.com/books/1234000000262/index.html" }, { isbn: "9781593275846", title: "Eloquent JavaScript, Second Edition", subtitle: "A Modern Introduction to Programming", author: "Marijn Haverbeke", publish_date: "2014-12-14T00:00:00.000Z", publisher: "No Starch Press", pages: 472, description: "JavaScript lies at the heart of almost every modern web application, from social apps to the newest browser-based games. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex language that you can use to build full-scale ", website: "http://eloquentjavascript.net/" }, { isbn: "9781593277574", title: "Understanding ECMAScript 6", subtitle: "The Definitive Guide for JavaScript Developers", author: "Nicholas C. Zakas", publish_date: "2016-09-03T00:00:00.000Z", publisher: "No Starch Press", pages: 352, description: "ECMAScript 6 represents the biggest update to the core of JavaScript in the history of the language. In Understanding ECMAScript 6, expert developer Nicholas C. Zakas provides a complete guide to the object types, syntax, and other exciting changes that E", website: "https://leanpub.com/understandinges6/read" } ]}
错误的填充代码
let obj1 = { isbn: "", title: "" } let array1 = [] for (var i=0; i < objPractica.books.length - 1; i++) { obj1.isbn = objPractica.books[i].isbn obj1.title = objPractica.books[i].title array1.push(obj1) } console.log("The array [] that contains object with format {a:'value', b:'value'} is: ", array1)
得到的错误结果
The array [] that contains object with format {a:'value', b:'value'} is: [ { isbn: '9781593275846', title: 'Eloquent JavaScript, Second Edition' }, { isbn: '9781593275846', title: 'Eloquent JavaScript, Second Edition' }, { isbn: '9781593275846', title: 'Eloquent JavaScript, Second Edition' }, { isbn: '9781593275846', title: 'Eloquent JavaScript, Second Edition' }, { isbn: '9781593275846', title: 'Eloquent JavaScript, Second Edition' }, { isbn: '9781593275846', title: 'Eloquent JavaScript, Second Edition' }, { isbn: '9781593275846', title: 'Eloquent JavaScript, Second Edition' } ]
原因分析
JavaScript中,对象属于引用类型,而非值类型。你在循环外只创建了一次obj1对象,每次循环只是修改这个对象的isbn和title属性,然后把这个对象的引用推入数组。也就是说,数组里的所有元素其实都指向同一个内存地址的对象,最后一次循环修改完属性后,数组里所有引用指向的都是这个最终状态的对象,所以显示的全是最后一次修改的值。
另外代码还有两个小问题:
- 变量名拼写错误:
objPractica应该是objPractice - 循环条件
i < objPractice.books.length - 1会导致最后一个元素被跳过,应改为i < objPractice.books.length
修复方案
方案1:在循环内创建新对象
每次循环都新建一个对象,确保每个推入数组的对象都是独立的:
let array1 = [] for (var i=0; i < objPractice.books.length; i++) { let obj1 = { isbn: "", title: "" } obj1.isbn = objPractice.books[i].isbn obj1.title = objPractice.books[i].title array1.push(obj1) }
方案2:直接在push时创建对象
省去提前声明对象的步骤,代码更简洁:
let array1 = [] for (var i=0; i < objPractice.books.length; i++) { array1.push({ isbn: objPractice.books[i].isbn, title: objPractice.books[i].title }) }
方案3:使用Array.map方法(推荐)
利用数组的map方法直接转换元素,代码简洁易读:
let array1 = objPractice.books.map(book => ({ isbn: book.isbn, title: book.title }))
内容的提问来源于stack exchange,提问作者German Larcher
相关产品推荐
相关产品推荐

