Angular.js: $ eval ทำงานอย่างไรและทำไมจึงแตกต่างจาก vanilla eval


151

ฉันอยากรู้เกี่ยวกับ$scope.$evalคุณที่มักจะเห็นในคำสั่งดังนั้นฉันตรวจสอบแหล่งที่มาและพบสิ่งต่อไปนี้ในrootScope.js:

  $eval: function(expr, locals) {
    return $parse(expr)(this, locals);
  },

$parseดูเหมือนจะถูกกำหนดโดยParseProviderในparse.jsซึ่งดูเหมือนว่าจะกำหนดรูปแบบของมินิซินของตัวเอง (ไฟล์มีความยาว 900 บรรทัด)

คำถามของฉันคือ:

  1. กำลัง$evalทำอะไรกันแน่ ทำไมมันต้องใช้ภาษาแยกวิเคราะห์ขนาดเล็กของตัวเอง?

  2. ทำไมไม่ธรรมดาเก่า JavaScript evalถูกนำมาใช้?


13
$ EVAL ประเมินเชิงมุมแสดงออกต่อต้าน / ในขอบเขตปัจจุบัน
Mark Rajcok

4
BTW $parseนั้นยอดเยี่ยมมาก
Fresheyeball

คำตอบ:


186

$evalและ$parseไม่ประเมิน JavaScript พวกเขาประเมิน AngularJS แสดงออก เอกสารที่เชื่อมโยงจะอธิบายความแตกต่างระหว่างนิพจน์และ JavaScript

ถาม: $ eval กำลังทำอะไรอยู่? ทำไมมันต้องใช้ภาษาแยกวิเคราะห์ขนาดเล็กของตัวเอง?

จากเอกสาร:

นิพจน์เป็นตัวอย่างโค้ด JavaScript ที่มักจะวางไว้ในการผูกเช่น {{expression}} นิพจน์นั้นประมวลผลโดยบริการ $ parse

มันเป็นเหมือนมินิภาษาจาวาสคริปต์ที่ จำกัด สิ่งที่คุณสามารถเรียกใช้ (เช่นไม่มีคำสั่งควบคุมการไหลยกเว้นผู้ประกอบการที่ประกอบไปด้วยสาม) รวมทั้งเพิ่มความดีของ AngularJS (เช่นตัวกรอง)

ถาม: ทำไมจึงไม่ใช้จาวาสคริปต์แบบธรรมดา "eval"

เพราะมันไม่ได้ประเมิน JavaScript ตามที่เอกสารระบุไว้:

หาก ... คุณต้องการเรียกใช้รหัส JavaScript ตามอำเภอใจคุณควรทำให้เป็นตัวควบคุมและเรียกใช้เมธอด หากคุณต้องการ eval () นิพจน์เชิงมุมจาก JavaScript ใช้เมธอด $ eval ()

เอกสารที่ลิงก์ไปด้านบนมีข้อมูลมากขึ้น


คุณบอกว่า $ eval ไม่ได้ประเมิน JavaScript จริงๆ แต่ถ้าฉันทำ $ eval ("{id: 'val'}") ฉันจะได้รับวัตถุ JS (เชิงมุม 1.0.8)
กาเบรียล

7
@Yappli $evalไม่ได้ประเมิน JavaScript มันประเมินการแสดงออกของ AngularJS ซึ่งเป็นเหมือนส่วนย่อยที่ปลอดภัยของ JavaScript "{id: 'val'}"เป็นนิพจน์ AngularJS ที่ถูกต้องและควรส่งคืนวัตถุ JS ที่ถูกต้อง ดูลิงก์ด้านบนสำหรับความแตกต่างระหว่างนิพจน์และ JS ปกติ
Josh David Miller

1
คำตอบที่ดี แต่ฉันไม่แน่ใจว่า "เช่นไม่มีคำสั่งควบคุมการไหล" ถูกต้อง คุณสามารถทำอะไรเช่นนี้ ... ng-click = "someVal? someFunc (someVal): noop" ซึ่งเป็นนิพจน์เชิงมุมที่ถูกต้องสมบูรณ์
Charlie Martin

@CharlieMartin เอกสารระบุว่า"ไม่มีคำสั่งควบคุมการไหล"โดยเฉพาะ แต่จุดของคุณนั้นถูกต้อง อย่างไรก็ตามฉันไม่แนะนำให้ทำอย่างนั้นใน ngClick; ตรรกะชนิดนั้นเกือบจะแน่นอนอยู่ในตัวควบคุม
Josh David Miller

1
น่าสนใจที่เอกสารบอกว่าขณะที่การสนับสนุนสำหรับผู้ประกอบการที่ประกอบไปด้วยถูกเพิ่มเข้ามาโดยเจตนา ... github.com/angular/angular.js/blob/master/src/ng/…การคลิก ng เป็นเพียงตัวอย่างง่ายๆและฉันเห็นด้วย ตรรกะนั้นควรอยู่ในตัวควบคุม แต่ฉันไม่เห็นอะไรผิดปกติกับการใช้ตัวดำเนินการประกอบไปด้วยสัญกรณ์วงเล็บและทีมงานเชิงมุมเห็นได้ชัดว่าไม่เช่นนั้นหรือพวกเขาจะไม่ได้เพิ่มการสนับสนุน ผมคิดว่าถ้าการแก้ไขที่ถูกที่จะทำมันจะเกิดขึ้นในเอกสารก่อนหน้านี้คำตอบแม้ว่า
ชาร์ลีมาร์ติน

22

จากการทดสอบ

it('should allow passing locals to the expression', inject(function($rootScope) {
  expect($rootScope.$eval('a+1', {a: 2})).toBe(3);

  $rootScope.$eval(function(scope, locals) {
    scope.c = locals.b + 4;
  }, {b: 3});
  expect($rootScope.c).toBe(7);
}));

นอกจากนี้เรายังสามารถส่งผ่านคนในท้องถิ่นสำหรับการแสดงออกการประเมินผล


2

ฉันคิดว่าหนึ่งในคำถามดั้งเดิมที่นี่ไม่ได้รับคำตอบ ฉันเชื่อว่าไม่ใช้ vanilla eval () เนื่องจากแอปเชิงมุมจะไม่ทำงานเป็นแอป Chrome ซึ่งป้องกันไม่ให้ eval () ถูกใช้เพื่อเหตุผลด้านความปลอดภัยอย่างชัดเจน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.