ทำไมเฟรมเวิร์ก / ไลบรารี JavaScript มีฟังก์ชั่นที่มีอยู่แล้วในจาวาสคริปต์แท้?


60

ฉันสงสัยว่าทำไมเฟรมเวิร์ก / ห้องสมุดมีผู้ช่วยเหลือเป็นของตัวเอง

ลองทำjQueryและAngularJSกัน พวกเขามีeachฟังก์ชั่นตัววนซ้ำของตัวเอง:

Array.prototype.forEachแต่เรามี

ในทำนองเดียวกัน

แต่เรามีJSON.parse()ฟังก์ชั่นใน JavaScript วานิลลา


75
ในฐานะที่เป็นคนที่จดจำวันที่เลวร้ายของการพัฒนาเว็บไซต์คำถามนี้ทำให้ฉันร้องไห้
josh3736

3
@ josh3736 อย่างน้อยคุณก็ยังไม่จำเป็นต้องรองรับ IE6 ('tho โชคดีเฉพาะใน "ทำให้มันทำงานได้ดูเหมือนเป็นอึ")
Izkata

12
jQuery.eachและArray.prototype.forEachไม่เทียบเท่า
zzzzBov

3
สิ่งที่คุณควรถามตัวเองคือ: เท่าไหร่ฟังก์ชั่นที่พบใน vanillaJS ตอนนี้มาจากชุดเครื่องมือเช่น jQ และชอบ? คำตอบคือ: จำนวนมาก สิ่งนี้จะถามคำถาม: ทำไมเราถึงยังใช้มันอยู่ เหตุใดจึงต้องรวม jQuery's $.eachและไม่ใช้ภาษาพื้นเมือง (และเร็วกว่า) Array.prototype.forEach?
Elias Van Ootegem

1
@ josh3736 ไม่เป็นไร bro ... i.stack.imgur.com/HJs4V.jpg
Crono

คำตอบ:


93

เนื่องจากเมื่อมีการเขียนไลบรารีเหล่านั้นเบราว์เซอร์หลักบางตัวจึงไม่สนับสนุนคุณสมบัติเหล่านั้น เมื่อเขียนและใช้แล้วฟีเจอร์เหล่านี้จะไม่สามารถลบออกจากไลบรารี่เหล่านี้ได้

(ในกรณีนี้ "เบราว์เซอร์หลัก" หมายถึงเบราว์เซอร์ที่ยังคงมีส่วนแบ่งการตลาดขนาดใหญ่ซึ่งรวมถึงเบราว์เซอร์รุ่นเก่าเช่น Internet Explorer ซึ่งผู้ใช้จำนวนมากไม่จำเป็นต้องอัพเกรดเป็นเวอร์ชั่นล่าสุด)


44
$ ('marquee'). แต่ละส่วน (ฟังก์ชั่น () {$ (นี้). ผนวก ($ ('<bgsound />', {src: "good-answer.mp3"}));});
Pierre Arlaud

36
@dirkk ไม่ใช่ว่าเบราว์เซอร์รุ่นล่าสุดไม่รองรับ ไม่ใช่ทุกคนที่โชคดีพอที่จะมีผู้ชมที่ใช้เบราว์เซอร์ล่าสุด
George Reith

14
Array.prototype.forEachวนซ้ำเฉพาะอาร์เรย์เท่านั้น - ทั้งสองฟังก์ชันไลบรารีตัววนซ้ำสามารถวนซ้ำอาร์เรย์หรือวัตถุได้
JoeG

3
มีฟังก์ชั่นเพื่อรองรับเบราว์เซอร์รุ่นเก่าและรองรับรหัสเก่าที่เรียกไลบรารี่และโปรแกรมเมอร์ไม่ต้องการเขียนใหม่ แม้ว่าคุณจะลดการสนับสนุน IE 6 คุณอาจยังคงมีการใช้งาน JavaScript บางอย่างเมื่อคุณไม่จำเป็นต้องสนับสนุนสำเนาโบราณของ IE
Michael Shopsin

6
ฟังก์ชันนี้มากมาย (เช่น jQuery.parseJSON ()) เพียงตรวจสอบว่าเบราว์เซอร์รองรับหรือไม่จากนั้นตั้งค่าเป็นวิธีเบราว์เซอร์และใช้ทางเลือกอื่นบนเบราว์เซอร์ที่ไม่รองรับเท่านั้น!
Josef

35

เนื่องจากเบราว์เซอร์ที่แตกต่างกันมีการใช้งานและคุณสมบัติที่แตกต่างกันในเอนจิ้น JavaScript รหัส "vanilla-JS" เดียวกันสามารถทำงานแตกต่างกันในเบราว์เซอร์ที่แตกต่างกันสองแห่งหรือแม้แต่เบราว์เซอร์รุ่นเดียวกันสองรุ่น

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

สิ่งนี้ทำให้ชีวิตง่ายขึ้นมากสำหรับนักพัฒนาที่สามารถมุ่งเน้นไปที่โค้ดที่ควรทำแทนที่จะเขียนให้ทำงานกับเบราว์เซอร์ X หรือ Y


2
พฤติกรรมของ "core JS" นั้นมีการระบุและทดสอบอย่างดีในทุกเบราว์เซอร์
Domenic

2
@Domenic Syntax นอกเหนือจากการใช้งานจาวาสคริปต์จะแตกต่างจากเบราว์เซอร์ไปยังเบราว์เซอร์ มีคุณสมบัติวิธีการเหตุการณ์และคุณสมบัติที่คุณจะพบในเบราว์เซอร์เพียงไม่กี่เท่านั้นหรือแม้กระทั่งในบางครั้ง
Crono

1
ใช่เบราว์เซอร์มีคุณสมบัติที่ไม่เป็นมาตรฐาน ที่ไม่เกี่ยวข้องกับคุณสมบัติมาตรฐานที่กล่าวถึงในคำถามนี้
Domenic

8
@Domenic หากโดย "คุณสมบัติมาตรฐานที่กล่าวถึงในคำถาม" คุณหมายถึงArray.prototype.forEachและJSON.parseฟังก์ชั่นการค้นหาอย่างรวดเร็วบน Google จะแสดงให้คุณเห็นว่าคุณผิด JSONไม่รองรับวัตถุใน IE7 และforEachไม่ได้กำหนดในบางเวอร์ชันของ Opera อย่างไรก็ตามไลบรารีเช่น jQuery รู้เกี่ยวกับข้อ จำกัด เหล่านี้และทำงานอยู่เบื้องหลังพวกเขาเบื้องหลัง ดังนั้นฉันคิดว่าคำตอบของฉันยังคงอยู่
Crono

27

1. ความเข้ากันได้ย้อนหลัง

JavaScript คือการดำเนินการECMAScript ฟังก์ชั่นเหล่านั้นส่วนใหญ่ได้รับการแนะนำใน ECMAScript 5 (ES5) อย่างไรก็ตามเบราว์เซอร์รุ่นเก่าจำนวนมากซึ่งยังมีส่วนแบ่งตลาดที่สำคัญพอไม่รองรับฟังก์ชั่นเหล่านี้ (ดูตารางความเข้ากันได้ ECMAScript 5 )

โดยทั่วไปแล้วไลบรารี่จะกลับไปใช้งานเนทีฟหากมีอยู่แล้วใช้โพลีฟิลของตัวเองตัวอย่างเช่นลองดูการใช้งานของ AngularJS ( angular.js L203-257 ):

function forEach(obj, iterator, context) {
  var key;
  if (obj) {
    if (isFunction(obj)){
      for (key in obj) {
        // Need to check if hasOwnProperty exists,
        // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
        if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
          iterator.call(context, obj[key], key);
        }
      }
    } else if (obj.forEach && obj.forEach !== forEach) {
      obj.forEach(iterator, context);
    } else if (isArrayLike(obj)) {
      for (key = 0; key < obj.length; key++)
        iterator.call(context, obj[key], key);
    } else {
      for (key in obj) {
        if (obj.hasOwnProperty(key)) {
          iterator.call(context, obj[key], key);
        }
      }
    }
  }
  return obj;
}

บรรทัดต่อไปนี้ตรวจสอบว่ามีforEachเมธอดอยู่บนวัตถุหรือไม่และเป็นรุ่น AngularJS หรือไม่ หากไม่ใช้ฟังก์ชันที่ระบุไว้แล้ว (เวอร์ชั่นเนทิฟ):

} else if (obj.forEach && obj.forEach !== forEach) {
  obj.forEach(iterator, context);
}

2. ความสะดวกสบาย

ในภาษาจาวาสคริปต์Array.prototype.forEachนั้นเป็นวิธีการเฉพาะสำหรับอินสแตนซ์Arrayอย่างไรก็ตามส่วนใหญ่ใด ๆObjectiterable เกินไป

ด้วยเหตุนี้ผู้สร้างห้องสมุดจำนวนมากจึงทำหน้าที่หลากหลาย (สามารถรับได้หลายประเภทเป็นอินพุต) ลองดูโค้ด AngularJS ด้านบนและดูว่าอินพุตอะไรยอมรับ:

ฟังก์ชั่น :

if (isFunction(obj)){
  for (key in obj) {
    // Need to check if hasOwnProperty exists,
    // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
    if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
      iterator.call(context, obj[key], key);
    }
  }

อาร์เรย์ (พร้อมการสนับสนุนพื้นเมืองสำหรับแต่ละคน):

} else if (obj.forEach && obj.forEach !== forEach) {
  obj.forEach(iterator, context);

Array-like objectsรวมถึง Array (ที่ไม่มีการสนับสนุนสำหรับแต่ละภาษา), String, HTMLElement, Object ที่มีคุณสมบัติความยาวที่ถูกต้อง:

} else if (isArrayLike(obj)) {
  for (key = 0; key < obj.length; key++)
    iterator.call(context, obj[key], key);

วัตถุที่:

} else {
  for (key in obj) {
    if (obj.hasOwnProperty(key)) {
      iterator.call(context, obj[key], key);
    }
  }
}

ข้อสรุป

ในขณะที่คุณสามารถเห็น AngularJS จะวนซ้ำวัตถุ JavaScript ส่วนใหญ่แม้ว่ามันจะทำงานในลักษณะเดียวกับฟังก์ชั่นพื้นเมืองมันยอมรับประเภทของการป้อนข้อมูลที่แตกต่างกันมากขึ้นดังนั้นจึงเป็นการเพิ่มที่ถูกต้องไปยังห้องสมุดเช่นเดียวกับวิธีการนำฟังก์ชั่น ES5 สู่เบราว์เซอร์รุ่นเก่า


2
คุณอาจต้องการอัปเดตลิงก์ของคุณให้ชี้ไปที่การส่งข้อความเฉพาะ (เช่นangular.js L203-257 ) สำหรับการอ้างอิงในอนาคตเมื่อมีmasterการเปลี่ยนแปลง
Whymarrh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.