เหตุใด“ ใช้เข้มงวด” ปรับปรุงประสิทธิภาพ 10x ในตัวอย่างนี้


128

ต่อไปนี้เป็นคำถามที่ขยายประสิทธิภาพ String.prototypeฉันกำลังทึ่งจริงๆเพราะเพียงการเพิ่ม"use strict"กับString.prototypeประสิทธิภาพการทำงานวิธีการที่ดีขึ้น 10 ครั้ง คำอธิบายโดยbergiเป็นระยะสั้นและไม่ได้อธิบายให้ฉัน ทำไมถึงมีความแตกต่างอย่างมากระหว่างสองวิธีที่เหมือนกันเกือบจะแตกต่างกัน"use strict"ที่ด้านบนเท่านั้น? คุณสามารถอธิบายรายละเอียดเพิ่มเติมและทฤษฎีที่อยู่เบื้องหลังสิ่งนี้ได้ไหม?

String.prototype.count = function(char) {
  var n = 0;
  for (var i = 0; i < this.length; i++)
    if (this[i] == char) n++;
  return n;
};

String.prototype.count_strict = function(char) {
  "use strict";
  var n = 0;
  for (var i = 0; i < this.length; i++)
    if (this[i] == char) n++;
  return n;
};
// Here is how I measued speed, using Node.js 6.1.0

var STR = '0110101110010110100111010011101010101111110001010110010101011101101010101010111111000';
var REP = 1e4;

console.time('proto');
for (var i = 0; i < REP; i++) STR.count('1');
console.timeEnd('proto');

console.time('proto-strict');
for (var i = 0; i < REP; i++) STR.count_strict('1');
console.timeEnd('proto-strict');

ผลลัพธ์:

proto: 101 ms
proto-strict: 7.5 ms

1
คุณสามารถทำการทดสอบด้วยthis[i] === charและดูว่าคุณได้รับความแตกต่างกันหรือไม่?
Niet the Dark Absolute

1
ฉันทดสอบกับthis[i] === charสภาพแวดล้อม DOM และผลลัพธ์จะเหมือนกัน
Cristian Traìna

2
คำอธิบายของ bergi บอกว่าเมื่อคุณเรียกใช้countฟังก์ชันthisพารามิเตอร์จะต้องถูกส่งไปยังวัตถุสตริงแทนสตริงตัวอักษรในขณะที่อยู่ในโหมดเข้มงวดไม่จำเป็นต้องดำเนินการอย่างถูกต้อง ทำไมเป็นกรณีนี้เกินฉันฉันสนใจคำตอบ
Nick Larsen

3
@NickLarsen: เป็นเพียงภาษาที่ใช้ในการระบุ ตามเนื้อผ้า JS จะทำให้แน่ใจว่าคุณมักจะมีวัตถุเป็นthisแต่ในโหมดเข้มงวดมันข้ามขั้นตอนนั้นเพื่อให้คุณได้รับดั้งเดิมthisสตริงหรือสิ่งที่ได้รับการจัดเตรียมไว้ให้

6
ถึงเวลาที่จะนำ"use strict";เด็ก ๆ ไปทุกที่! Goooold
Jonathan

คำตอบ:


155

ในโหมดเข้มงวดthisบริบทไม่ได้ถูกบังคับให้เป็นวัตถุ ถ้าคุณเรียกใช้ฟังก์ชันบนวัตถุที่ไม่ใช่thisก็จะไม่ใช่วัตถุ

ในทางตรงกันข้ามในโหมดที่ไม่เข้มงวดthisบริบทจะถูกรวมไว้ในวัตถุก่อนเสมอหากยังไม่ได้เป็นวัตถุ ตัวอย่างเช่นการ(42).toString()แรป42ในNumberวัตถุก่อนแล้วจึงเรียกNumber.prototype.toStringด้วยNumberวัตถุเป็นthisบริบท ในโหมดเข้มงวดthisบริบทที่เหลือโทรแตะต้องและเพียงแค่Number.prototype.toStringมี42เป็นthisบริบท

(function() {
  console.log(typeof this);
}).call(42); // 'object'

(function() {
  'use strict';
  console.log(typeof this);
}).call(42); // 'number'

ในกรณีของคุณรุ่นของโหมดที่ไม่เข้มงวดใช้เวลามากในการห่อเวลาและแกะดั้งเดิมstringเข้าไปในStringห่อวัตถุและด้านหลัง ในขณะที่รุ่นโหมดเข้มงวดจะทำงานโดยตรงกับรุ่นดั้งเดิมstringซึ่งจะปรับปรุงประสิทธิภาพ


1
และการลบwithยังช่วยเล็กน้อยสำหรับทุกตัวแปรการค้นหา iirc
zzzzBov

2
@zzzzBov ไม่ถูกต้อง การลบwithจะช่วยได้อย่างมากเนื่องจากช่วยให้เบราว์เซอร์สามารถให้เหตุผลว่านิพจน์ตัวแปรหมายถึงตัวแปรใด
John Dvorak

2
ดูเหมือนว่าฉันไม่ได้ใช้งานง่ายเลยว่าการไม่ใช้วัตถุthisนั้น "เข้มงวด" กว่าการใช้วัตถุthisตลอดเวลา
IllidanS4 ต้องการโมนิก้ากลับเมื่อ

2
@ IllidanS4: ส่วนใหญ่เกี่ยวกับกรณีที่thisเป็นnullหรือundefinedซึ่งจะเป็นวัตถุระดับโลกในโหมดเลอะเทอะ
Bergi

6
@ IllidanS4: คิดว่ามันเป็น "ของจริงthis" กับ "เสื้อคลุมthis" หากคุณต้องการ วัตถุที่ห่อหุ้มเป็น kludge ที่ไม่ควรมีตัวตนดังนั้นจึงเหมาะสมที่โหมดที่เข้มงวดจะหลีกเลี่ยงพวกมันมากขึ้นเมื่อเป็นไปได้
Ry-
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.