Angular.js: Bagaimana cara kerja $ eval dan mengapa ini berbeda dari vanilla eval?

151

Saya ingin tahu tentang $scope.$evalAnda yang sering dilihat dalam arahan, jadi saya memeriksa sumbernya dan menemukan yang berikut di rootScope.js:

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

$parsetampaknya didefinisikan oleh ParseProviderin parse.js, yang tampaknya mendefinisikan beberapa jenis sintaks mini sendiri (panjang file 900 baris).

Pertanyaan saya adalah:

  1. Apa yang sedang $evaldilakukan? Mengapa perlu bahasa parsing mini sendiri?

  2. Mengapa JavaScript lama evaltidak digunakan?

Jonah
sumber
13
$ eval mengevaluasi ekspresi Angular terhadap / pada lingkup saat ini .
Mark Rajcok
4
BTW $parseluar biasa hebat.
Fresheyeball

Jawaban:

186

$evaldan $parsejangan mengevaluasi JavaScript; mereka mengevaluasi ekspresi AngularJS . Dokumentasi tertaut menjelaskan perbedaan antara ekspresi dan JavaScript.

T: Apa yang sebenarnya dilakukan $ eval? Mengapa perlu bahasa parsing mini sendiri?

Dari dokumen:

Ekspresi adalah cuplikan kode seperti JavaScript yang biasanya ditempatkan di binding seperti {{ekspresi}}. Ekspresi diproses oleh layanan $ parse.

Ini adalah bahasa mini seperti JavaScript yang membatasi apa yang dapat Anda jalankan (mis. Tidak ada pernyataan aliran kontrol, kecuali operator ternary) serta menambahkan beberapa kebaikan AngularJS (mis. Filter).

T: Mengapa javascript lama biasa "eval" tidak digunakan?

Karena itu sebenarnya tidak mengevaluasi JavaScript. Seperti yang dikatakan para dokter:

Jika ... Anda ingin menjalankan kode JavaScript sewenang-wenang, Anda harus menjadikannya sebagai metode pengontrol dan memanggil metode tersebut. Jika Anda ingin eval () ekspresi sudut dari JavaScript, gunakan metode $ eval ().

Dokumen yang ditautkan ke atas memiliki lebih banyak informasi.

Josh David Miller
sumber
Anda bilang $ eval tidak benar-benar mengevaluasi JavaScript tetapi jika saya melakukan $ eval ("{id: 'val'}") saya mendapatkan objek JS. (Angular 1.0.8)
Gabriel
7
@Yappli $evaltidak mengevaluasi JavaScript; itu mengevaluasi ekspresi AngularJS, yang merupakan semacam bagian yang lebih aman dari JavaScript. "{id: 'val'}"adalah ekspresi AngularJS yang valid dan harus mengembalikan objek JS yang valid. Lihat tautan di atas untuk perbedaan antara ekspresi dan JS biasa.
Josh David Miller
1
Jawaban yang bagus tapi saya tidak yakin bahwa "misalnya tidak ada pernyataan aliran kontrol" akurat. Anda dapat melakukan sesuatu seperti ini ... ng-klik = "someVal? SomeFunc (someVal): noop" yang merupakan ekspresi sudut yang benar-benar valid
Charlie Martin
@CharlieMartin Dokumentasi secara khusus mengatakan "tidak ada pernyataan aliran kontrol" , tetapi poin Anda valid. Namun, saya pasti tidak akan merekomendasikan melakukan itu di ngClick; logika semacam itu hampir pasti termasuk dalam pengontrol.
Josh David Miller
1
Menarik bahwa dokumen mengatakan bahwa sebagai dukungan untuk operator ternary sengaja ditambahkan ... github.com/angular/angular.js/blob/master/src/ng/ ... Ng-klik hanyalah contoh sederhana dan saya setuju logika itu harus di controller, tapi saya tidak melihat ada yang salah dengan menggunakan operator ternary di notasi braket dan tim sudut jelas tidak baik atau mereka tidak akan menambahkan dukungan untuk itu. Saya kira jika koreksi harus dilakukan, itu harus terjadi dalam dokumen sebelum jawaban ini
Charlie Martin
22

Dari tes,

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

Kami juga dapat melewati penduduk setempat untuk ekspresi evaluasi.

allenhwkim
sumber
2

Saya pikir salah satu pertanyaan asli di sini tidak dijawab. Saya percaya bahwa vanilla eval () tidak digunakan karena aplikasi bersudut maka tidak akan berfungsi sebagai aplikasi Chrome, yang secara eksplisit mencegah eval () digunakan untuk alasan keamanan.

Kevin MacDonald
sumber