คำถามสัมภาษณ์ Javascript: make [1,2,3] .sum () run

Nov 17 2020

Javascript คำถามสัมภาษณ์: ให้[1,2,3].sum()รหัสการทำงานที่แน่นอนโดยไม่ต้องใช้Prototypeและ,Object.definePropertyObject.defineProperties

เนื่องจากเป็นคำถามสัมภาษณ์ฉันจึงคิดว่ามีวิธีที่จะทำให้มันได้ผลหรือไม่?

ขอความช่วยเหลือ / ชี้ทิศทางใด ๆ ที่ชื่นชม

ขอบคุณ

คำตอบ

8 Dai Nov 17 2020 at 03:09

คำนำ: คำถามเหล่านี้ไม่ได้แสดงว่าใครเป็นโปรแกรมเมอร์ที่ "เก่ง" แต่ก็หมายความว่าพวกเขาคุ้นเคยกับกลเม็ดในภาษาที่ไม่ได้นำไปสู่รหัสที่ดูแลรักษาได้มากขึ้น ฉันระวังการทำงานให้กับ บริษัท หรือทีมที่ใช้กลอุบายเช่นนี้เป็นประจำ

(และในกรณีส่วนตัวของฉัน: ฉันทำงานกับ Chakra JavaScript engine เมื่อฉันเป็น SE ที่ Microsoft และฉันชอบคิดว่าฉันรู้จัก JavaScript / ECMAScript เป็นอย่างดีและฉันยังคงต้องคิดอยู่นานว่าจะทำได้อย่างไรหากไม่มี การใช้prototypeหรือdefineProperty- นั่นคือเหตุผลที่ฉันไม่คิดว่านี่เป็นคำถามสัมภาษณ์ทางเทคนิคที่ดีหากพวกเขาคาดหวังคำตอบที่ตรง - แต่ถ้านี่เป็นคำถามสัมภาษณ์ที่ตั้งใจให้คุณถามคำถามของผู้สัมภาษณ์ก็จะแตกต่างออกไป)


ตัวเลือกที่ 1: ตัวจัดการข้อผิดพลาดส่วนกลาง:

นี่เป็นวิธีที่น่ากลัว :

window.addEventListener( 'error', function( e ) {
    
    if( e.error instanceof ErrorEvent || e.error instanceof TypeError ) {
        
        const msg = e.error.message;
        const suffixIdx = msg.indexOf( ".sum is not a function" );
        if( suffixIdx > -1 ) {
            const arrayStr = msg.substring( 0, suffixIdx );
            
            const arr = eval( arrayStr ); // <-- lolno
            const total = arr.reduce( ( sum, e ) => sum + e, 0 );
            console.log( total ); // 6
        }
    }
    
} );

[1,2,3].sum()


@NenadVracar ได้โพสต์เวอร์ชันที่เรียบง่ายที่หลีกเลี่ยงevalแม้ว่าจะใช้โลคัลtry:

try {
    [1,2,3].sum()
} catch (err) {
    const result = err.message
    .match(/\[(.*?)\]/)[1]
    .split(',')
    .reduce((r, e) => r + +e, 0)
    
  console.log(result)
}

ตัวเลือกที่ 2: แทนที่ตัวArrayสร้าง

หากคุณใช้ JavaScript Engine รุ่นเก่า (สร้างขึ้นก่อนปี 2010 หรือ ECMAScript 5)สคริปต์ที่แทนที่ตัวArrayสร้างจะมีตัวสร้างที่ใช้เมื่อสคริปต์พบอาร์เรย์ลิเทอรัลและ.sumสามารถเพิ่มเมธอดด้วยวิธีนี้:

Array = function() { // <-- THIS WILL NOT WORK IN BROWSERS MADE AFTER 2010!
    this.sum = function() {
        var total = 0;
        for( var i = 0; i < this.length; i++ ) {
            total += this[i];
        }
        return total;
    };
};

let total = [1,2,3].sum();
console.log( total );

ตัวเลือกที่ 3: การส่อเสียดกับprototypeทรัพย์สิน:

ดังที่คนอื่น ๆ ได้กล่าวไว้ในความคิดเห็นคุณยังคงสามารถเปลี่ยนprototypeสมาชิกหรือใช้Object.definePropertyหากคุณเข้าถึงสมาชิกเหล่านั้นเป็นสตริง:

Array[ 'proto' + 'type' ].sum = function() {
    var total = 0;
    for( var i = 0; i < this.length; i++ ) {
        total += this[i];
    }
    return total;
};

let total = [1,2,3].sum();
console.log( total );

6 VLAZ Nov 17 2020 at 03:26

เราสามารถกระโปรงเส้นตรงนี้ได้มากแค่ไหน?

สมมติว่าเราต้องการบรรทัดต่อไปนี้ในการทำงาน[1, 2, 3].sum();แล้วเราสามารถได้อย่างง่ายดายมากเพียงแค่ให้มันทำบางสิ่งบางอย่าง โปรดทราบว่าเนื่องจากกฎการแทรกอัฒภาคอัตโนมัติคุณจึงไม่จำเป็นต้องมีอาร์เรย์ อาจเป็นการเข้าถึงอาร์เรย์โดยมีตัวดำเนินการลูกน้ำอยู่

({3: {sum: () => console.log(6)}}) //<-- object

[1,2,3].sum(); //<-- array access

หรือเพื่อให้ชัดเจนยิ่งขึ้นนี่คือรหัสที่เทียบเท่า:

const obj = {
  3: {
    sum: () => console.log(6)
  }
};

obj[3].sum(); //<-- array access

เนื่องจากฉันไม่เห็นคำจำกัดความของสิ่งที่sumควรทำข้างต้นจึงครอบคลุมข้อกำหนดทั้งหมดที่ระบุไว้ - ไม่มีโปรโตไทป์เชนานิแกนไม่มีคุณสมบัติพิเศษ

ตกลงในทางเทคนิคsumไม่ได้สรุปอะไรเลย แต่นี่คือวิธีแก้ปัญหา: กำหนดแบบนี้

sum: (a, b) => a + b

ในทางเทคนิคแล้วมันเป็นฟังก์ชันที่รวมสองจำนวน ไม่มีข้อกำหนดที่จะรวมลำดับ1, 2, 3ที่ปรากฏก่อนที่จะเรียกsumหลังจากทั้งหมด

2 LuisLimas Nov 17 2020 at 03:06

นี่เป็นวิธีหนึ่ง:

 [1,2,3].__proto__.sum = () => { console.log('this runs!'); }
 
 [1,2,3].sum();

เทคนิคคุณไม่ได้ใช้Prototype, __proto__คุณกำลังใช้ Wich เหมือนกับชื่ออื่น ... (แต่สำหรับอินสแตนซ์เท่านั้น)