จะตรวจสอบว่าสตริง“ StartsWith” เป็นสตริงอื่นได้อย่างไร?


1690

ฉันจะเขียนเทียบเท่าของ C # ได้อย่างไร String.StartsWithใน JavaScript ได้อย่างไร

var haystack = 'hello world';
var needle = 'he';

haystack.startsWith(needle) == true

หมายเหตุ: นี่เป็นคำถามเก่าและตามที่ระบุไว้ในความคิดเห็น ECMAScript 2015 (ES6) แนะนำ.startsWithวิธีการ อย่างไรก็ตามในเวลาของการเขียนโปรแกรมปรับปรุงนี้ (2015) การสนับสนุนเบราว์เซอร์ที่อยู่ไกลจากที่สมบูรณ์

คำตอบ:


1773

คุณสามารถใช้ ECMAScript 6 String.prototype.startsWith()วิธี แต่ก็ยังไม่ได้รับการสนับสนุนในเบราว์เซอร์ คุณจะต้องการใช้ shim / polyfill เพื่อเพิ่มลงในเบราว์เซอร์ที่ไม่รองรับ การสร้างการใช้งานที่เป็นไปตามรายละเอียดทั้งหมดที่วางไว้ในข้อมูลจำเพาะนั้นซับซ้อนเล็กน้อย หากคุณต้องการชิมที่ซื่อสัตย์ให้ใช้:

เมื่อคุณกำหนดวิธีการ (หรือถ้าคุณสนับสนุนเบราว์เซอร์และเครื่องมือ JavaScript ที่มีอยู่แล้วเท่านั้น) คุณสามารถใช้วิธีนี้:

"Hello World!".startsWith("He"); // true

var haystack = "Hello world";
var prefix = 'orl';
haystack.startsWith(prefix); // false

@gtournie ทำไมจะเริ่มด้วยหนึ่งในวิธีที่แย่ที่สุดในการทดสอบว่าสตริงเริ่มต้นด้วยสตริงหรือไม่ (ดูความคิดเห็นของคุณที่นี่: stackoverflow.com/questions/646628/… ) คุณมีความกระตือรือร้นมากขึ้นเกี่ยวกับการเปรียบเทียบอักขระต่ออักขระ ฉันหวังว่าคอมไพเลอร์ฉลาดพอที่จะไม่สร้างสตริงสำหรับทุกสตริง [ดัชนี] เพราะถ้าคุณเพียงแค่เขียนนี้: character = string [0] มันจะจัดสรรวัตถุจะมีประสิทธิภาพน้อยกว่าการใช้ startsWith (startsWith จะไม่จัดสรรหน่วยความจำใด ๆ )
Martijn Scheffer

@MartijnScheffer: คำตอบได้รับการแก้ไขหลายครั้งตั้งแต่ฉันตอบและตอนนี้แตกต่างอย่างสิ้นเชิง (ฉันลบความคิดเห็นของฉัน;) ฉันยอมรับว่า ECMAScript 6 ของ startsWith เป็นวิธีที่ดีที่สุดในการทำเช่นนั้น
gtournie

6
@ GrahamLaight เมื่อคุณพูดว่าได้รับการสนับสนุนโดย 'IE' คุณคงหมายถึง Edge developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Marcus

@ Marcus ขอโทษถ้าฉันผิด - ข้อมูลของฉันมาจาก: w3schools.com/jsref/jsref_startswith.asp
Graham Laight

คำเตือน! การทดสอบ jsperf เหล่านี้ใช้ไม่ได้กับเบราว์เซอร์ที่ดีในการรวบรวม JIT เบราว์เซอร์เช่น Firefox และ Chrome บางครั้งจะรู้จักเมื่อผลลัพธ์ของการดำเนินการถูกละทิ้งดังนั้นจึงไม่สามารถดำเนินการได้ นอกจากนั้นเครื่องมือจาวาสคริปต์ที่ทันสมัยใช้การคาดคะเนสาขาดังนั้นสตริงการทดสอบควรแตกต่างกันในการทำซ้ำแต่ละครั้ง
Aloso

1282

ทางเลือกอื่นด้วย.lastIndexOf:

haystack.lastIndexOf(needle, 0) === 0

นี้ดูย้อนหลังผ่านhaystackสำหรับการเกิดขึ้นของneedleการเริ่มต้นจากดัชนีของ0 haystackในคำอื่น ๆ ก็จะตรวจสอบว่าเริ่มต้นด้วยhaystackneedle

โดยหลักการแล้วสิ่งนี้ควรมีความได้เปรียบด้านประสิทธิภาพมากกว่าวิธีอื่น ๆ :

  • haystackมันไม่ได้ค้นหาทั้งหมด
  • มันไม่ได้สร้างสตริงชั่วคราวใหม่แล้วละทิ้งมันทันที

1
ไม่แน่ใจว่ากรณีใด @ rfcoder89 กำลังจะเกิดขึ้น - jsfiddle.net/jkzjw3w2/1
Gulfaraz Rahman

5
@ rfcoder89 สังเกตว่าพารามิเตอร์ตัวที่สองของ lastIndexOf: "aba".lastIndexOf ("a")คือ 2 ตามที่คุณชี้ให้เห็น แต่"aba".lastIndexOf ("a", 0)เป็น 0 ซึ่งถูกต้อง
maxpolk

1
ขอบคุณมาก. String.startsWith ไม่ทำงานบน Android lollipop WebView แต่ตัวอย่างนี้ lastIndexOf ไม่ !!!
เฮอร์แมน

ด้วยlastIndexOfสตริงจะถูกค้นหาจากจุดเริ่มต้นจนถึงจุดเริ่มต้นดังนั้นจึงค้นหาสตริงทั้งหมด: ดังนั้นความไร้ประสิทธิภาพจึงเพิ่มขึ้นสำหรับการค้นหาสตริงที่ยาวมาก
willy wonka

8
@willywonka ไม่ไม่ใช่ถ้าคุณมี 0 startIndex จะค้นหาจาก 0 pos และเป็นเพียงการตรวจสอบเท่านั้น สตริงทั้งหมดจะถูกค้นหาก็ต่อเมื่อ fromIndex> = str.length
กรีนที่

588
data.substring(0, input.length) === input

3
@ ANAN ฉันสงสัยว่ามันขึ้นอยู่กับเบราว์เซอร์และข้อมูลที่ใช้ ดูคำตอบของ Ben Weaver สำหรับการวัดจริง ในเบราว์เซอร์ที่ฉันใช้งานในปัจจุบัน (Chrome 12.0.742 บน Windows) สตริงย่อยชนะเพื่อความสำเร็จและ regex ที่เตรียมไว้จะชนะเมื่อเกิดความล้มเหลว
cobbal

4
@cobbal บางที แต่.lastIndexOf(input, 0)เปรียบเทียบ N chars แรกในขณะที่.substring(0, input.length) === inputนับ N substrings ข้อมูลเป็นความยาว N แล้วเปรียบเทียบ N chars เหล่านั้น รุ่นที่สองนี้จะไม่สามารถทำงานได้เร็วกว่าโปรแกรมอื่น อย่าเข้าใจฉันผิดแม้ว่าฉันจะไม่พบสิ่งที่ดีกว่าที่คุณแนะนำด้วยตัวเอง :)
ตอบที่

2
@ ANeves แต่. lastIndexOf บนสตริงที่ยาวซึ่งจะส่งคืน false กำลังจะวนซ้ำไปทั่วทั้งสตริง (O (N)) ในขณะที่. substring case ทำซ้ำผ่านสตริงที่เล็กกว่ามาก หากคุณคาดหวังว่าเสียงส่วนใหญ่จะประสบความสำเร็จหรือมีเพียงอินพุตขนาดเล็ก. lastIndexOf ก็จะเร็วขึ้น .substring ยังมีข้อยกเว้นหากอินพุตยาวกว่าสตริงที่กำลังตรวจสอบ
Chris Moschini

14
@ChrisMoschini อย่าลืมว่าโซลูชัน Mark Byers ได้lastIndexOfเริ่มต้นที่ดัชนี 0 ไม่ใช่จุดสิ้นสุด นั่นทำให้ฉันสะดุด อย่างไรก็ตามการตรวจสอบว่าสตริงเริ่มต้นด้วยอะไรเป็นงานทั่วไปที่ JavaScript ควรมี API ที่เหมาะสมสำหรับมันไม่ใช่สำนวนและทางเลือกทั้งหมดที่คุณเห็นในหน้านี้
Randall Cook

4
ฉันชอบทางออกของ cobbal มากกว่า Mark แม้ว่าเครื่องหมายจะเร็วกว่าและเป็นกลอุบายที่น่าประทับใจเมื่อใช้ params มันยากมากที่จะอ่านเทียบกับสตริงย่อย
ThinkBonobo

184

หากไม่มีฟังก์ชั่นตัวช่วยเพียงใช้.testเมธอดของ regex :

/^He/.test('Hello world')

ในการทำเช่นนี้กับสตริงแบบไดนามิกแทนที่จะเป็นฮาร์ดโค้ด (สมมติว่าสตริงนั้นจะไม่มีอักขระควบคุม regexp):

new RegExp('^' + needle).test(haystack)

คุณควรตรวจสอบว่ามีฟังก์ชั่น RegExp.escape ใน Javascript หรือไม่? หากความเป็นไปได้มีอยู่ว่าตัวควบคุม regexp ปรากฏในสตริง


1
เพื่อที่จะทำให้การใช้งานที่สำคัญกรณีการแสดงออก/^he/i
kaizer1v

64

ทางออกที่ดีที่สุด:

function startsWith(str, word) {
    return str.lastIndexOf(word, 0) === 0;
}

และนี่คือที่สิ้นสุดหากคุณต้องการสิ่งนั้นด้วย:

function endsWith(str, word) {
    return str.indexOf(word, str.length - word.length) !== -1;
}

สำหรับผู้ที่ต้องการสร้างต้นแบบลงใน String:

String.prototype.startsWith || (String.prototype.startsWith = function(word) {
    return this.lastIndexOf(word, 0) === 0;
});

String.prototype.endsWith   || (String.prototype.endsWith = function(word) {
    return this.indexOf(word, this.length - word.length) !== -1;
});

การใช้งาน:

"abc".startsWith("ab")
true
"c".ensdWith("c") 
true

ด้วยวิธีการ:

startsWith("aaa", "a")
true
startsWith("aaa", "ab")
false
startsWith("abc", "abc")
true
startsWith("abc", "c")
false
startsWith("abc", "a")
true
startsWith("abc", "ba")
false
startsWith("abc", "ab")
true

ฉันคิดว่าคุณมั่วสุมกันครั้งสุดท้ายดัชนีและ indexOf ในฟังก์ชั่นของคุณ - startsWith ควรจะส่งคืน str.indexOf (คำ, 0) === 0;
Richard Matheson

5
@RichardMatheson ปัญหากับการใช้ indexOf คือถ้ามันไม่ตรงกับการเริ่มต้นมันจะทำการค้นหาสตริงทั้งหมดต่อไปโดย lastIndexOf เริ่มต้นจากความยาวของคำและเดินกลับไปที่ศูนย์ เข้าใจแล้วใช่ไหม
mmm

2
อ่าใช่แล้วตอนนี้ฉันไม่สนใจดัชนีที่คุณใช้อยู่ เคล็ดลับดีมาก!
Richard Matheson

54

ฉันแค่อยากจะเพิ่มความคิดเห็นเกี่ยวกับเรื่องนี้

ฉันคิดว่าเราสามารถใช้สิ่งนี้:

var haystack = 'hello world';
var needle = 'he';

if (haystack.indexOf(needle) == 0) {
  // Code if string starts with this substring
}

2
คำตอบของ Mark Byers ถูกนำมาเปรียบเทียบเพื่อประสิทธิภาพของวิธีการที่ถูกต้องสามวิธีโดย @relfor วิธีการที่ถูกต้องนี้ไม่ได้รับการสนับสนุนเนื่องจากต้องการค้นหาทั้งสตริง
maxpolk

@ maxpolk ฉันคิดว่าindexOfจะหยุดการค้นหาสตริงทั้งหมดเมื่อพบครั้งแรก ฉันได้ตรวจสอบแล้ว
Mr.D

8
หากไม่พบสิ่งที่เกิดขึ้นครั้งแรกที่จุดเริ่มต้นมากวิธีการนี้จะเริ่มไม่มีประสิทธิภาพมากขึ้นอีกต่อไปที่จะค้นหามันอาจค้นหาจนกว่าจะถึงจุดสิ้นสุดแทนการเลิกเร็วขึ้นมาก เนื่องจากมีศักยภาพในการไร้ประสิทธิภาพจึงไม่เป็นที่นิยมในแนวทางที่ถูกต้องทั้งสาม
maxpolk

2
@ Mr.D และถ้าไม่มีการแข่งขัน?
mmm

อื่นเมื่อกองหญ้าทั้งหมดถูกค้นหา? ดีกว่า: stackoverflow.com/a/36876507/961018 .. ค้นหาได้สูงสุดความยาวคำเท่านั้น
mmm

39

นี่คือการปรับปรุงเล็กน้อยในการแก้ปัญหาของ CMS:

if(!String.prototype.startsWith){
    String.prototype.startsWith = function (str) {
        return !this.indexOf(str);
    }
}

"Hello World!".startsWith("He"); // true

 var data = "Hello world";
 var input = 'He';
 data.startsWith(input); // true

การตรวจสอบว่าฟังก์ชั่นนั้นมีอยู่แล้วในกรณีที่เบราว์เซอร์ในอนาคตนำไปใช้กับโค้ดเนทีฟหรือมีการใช้งานโดยห้องสมุดอื่น ตัวอย่างเช่น Prototype Library ใช้ฟังก์ชันนี้แล้ว

การใช้!เร็วกว่าเล็กน้อยและกระชับกว่า=== 0ที่อ่านไม่ออก


1
นี่อาจเป็นปัญหา: หากการใช้งานในสถานที่มีพฤติกรรมแตกต่างจากของฉันเองสิ่งนี้จะทำให้ใบสมัครของฉันพัง
Christoph Wurm

2
ปัญหานี้มีปัญหา O (N) ที่กล่าวถึงที่นี่stackoverflow.com/questions/646628/javascript-startswith/ …
Chris Moschini

1
ใช้งาน! มีความยุ่งเหยิงมาก
JonnyRaa

-1; เพิ่มนี้String.prototypeเป็นความคิดที่ไม่ดีเพราะมันไม่ได้มาทุกที่ใกล้กับการปฏิบัติตามสเปคString.prototype.startsWithสำหรับ รหัสใด ๆ ที่พยายามใช้วิธี ES6 นั้นจะไม่สามารถทำได้หากคุณทำเช่นนี้ มันอาจดูดีเพื่อดูว่าวิธีการที่ถูกกำหนดไว้แล้วดูว่ามันเป็น (ไม่ดีโดยคุณ) และไม่เพิ่มในชิมมาตรฐานที่สอดคล้องกับที่นำไปสู่พฤติกรรมที่ไม่ถูกต้องในภายหลัง
Mark Amery

21

ยังตรวจสอบunderscore.string.js มันมาพร้อมกับพวงของการทดสอบสตริงที่มีประโยชน์และวิธีการจัดการรวมถึงstartsWithวิธีการ จากเอกสาร:

เริ่มต้นด้วย _.startsWith(string, starts)

วิธีนี้ตรวจสอบว่าstringเริ่มต้นด้วยstartsหรือไม่

_("image.gif").startsWith("image")
=> true

1
ฉันต้องการ_.string.startsWith
พันเอก Panic

15

ฉันเพิ่งถามตัวเองคำถามเดียวกัน
มีวิธีแก้ปัญหาที่เป็นไปได้หลายข้อต่อไปนี้เป็นแนวทางที่ถูกต้อง 3 ข้อ

  • s.indexOf(starter) === 0
  • s.substr(0,starter.length) === starter
  • s.lastIndexOf(starter, 0) === 0(เพิ่มหลังจากเห็นคำตอบของ Mark Byers )
  • ใช้วง:

    function startsWith(s,starter) {
      for (var i = 0,cur_c; i < starter.length; i++) {
        cur_c = starter[i];
        if (s[i] !== starter[i]) {
          return false;
        }
      }
      return true;
    }

ฉันยังไม่พบโซลูชันล่าสุดที่ใช้ประโยชน์จากลูป
น่าประหลาดใจที่โซลูชันนี้มีประสิทธิภาพเหนือกว่า 3 รายการแรกด้วยอัตรากำไรขั้นต้นที่สำคัญ
นี่คือการทดสอบ jsperf ที่ฉันดำเนินการเพื่อให้ได้ข้อสรุปนี้: http://jsperf.com/startswith2/2

สันติภาพ

ps: ecmascript 6 (สามัคคี) แนะนำstartsWithวิธีการดั้งเดิมสำหรับสายอักขระ
แค่คิดว่าจะประหยัดเวลาได้มากแค่ไหนถ้าพวกเขาคิดรวมถึงวิธีการที่จำเป็นในรุ่นเริ่มต้นด้วย

ปรับปรุง

ในฐานะที่เป็นสตีฟชี้ให้เห็น (ความคิดเห็นแรกในคำตอบนี้) ฟังก์ชั่นที่กำหนดเองข้างต้นจะโยนข้อผิดพลาดถ้าคำนำหน้าให้สั้นกว่าสตริงทั้งหมด เขาได้คงที่และเพิ่มการเพิ่มประสิทธิภาพห่วงซึ่งสามารถดูได้ที่http://jsperf.com/startswith2/4

โปรดทราบว่ามีการเพิ่มประสิทธิภาพลูป 2 แบบซึ่งสตีฟรวมอยู่ตัวแรกของทั้งสองแสดงประสิทธิภาพที่ดีกว่าดังนั้นฉันจะโพสต์โค้ดด้านล่างนี้:

function startsWith2(str, prefix) {
  if (str.length < prefix.length)
    return false;
  for (var i = prefix.length - 1; (i >= 0) && (str[i] === prefix[i]); --i)
    continue;
  return i < 0;
}

ดู rev ล่าสุด นอกเหนือจากข้อผิดพลาดในรุ่นด้านบน (มันจะโยนหากสตริงสั้นกว่าส่วนนำหน้า) ก็ช้ากว่ารุ่นที่ปรับให้เหมาะสมมากขึ้น ดูjsperf.com/startswith2/4และjsperf.com/js-startswith/35
Steve Hollasch

^ ขอบคุณที่ชี้ให้เห็นกรณีที่สตริงสั้นกว่าส่วนนำหน้า
Raj Nathani

jsperf.com/startswith2/29 => startsWith5 มีความกระชับและทำงานได้ดีจริง ๆ =)
gtournie

11

เนื่องจากนี่เป็นที่นิยมมากฉันคิดว่ามันคุ้มค่าที่ชี้ให้เห็นว่ามีการใช้งานสำหรับวิธีการนี้ใน ECMA 6 และในการเตรียมตัวสำหรับสิ่งนั้นควรใช้ polyfill 'อย่างเป็นทางการ' เพื่อป้องกันปัญหาและน้ำตาในอนาคต

โชคดีที่ผู้เชี่ยวชาญที่ Mozilla ให้เราด้วย:

https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith

if (!String.prototype.startsWith) {
    String.prototype.startsWith = function(searchString, position) {
        position = position || 0;
        return this.indexOf(searchString, position) === position;
    };
}

โปรดทราบว่านี่เป็นข้อดีของการไม่สนใจการเปลี่ยนมาใช้ ECMA 6


5

วิธีแก้ปัญหาที่ดีที่สุดคือหยุดใช้การโทรในห้องสมุดและเพิ่งรู้ว่าคุณกำลังทำงานกับสองอาร์เรย์ การใช้งานแบบรีดด้วยมือนั้นทั้งสั้นและเร็วกว่าโซลูชันอื่น ๆ ที่ฉันเคยเห็นที่นี่

function startsWith2(str, prefix) {
    if (str.length < prefix.length)
        return false;
    for (var i = prefix.length - 1; (i >= 0) && (str[i] === prefix[i]); --i)
        continue;
    return i < 0;
}

สำหรับการเปรียบเทียบผลการดำเนินงาน (ความสำเร็จและความล้มเหลว) ดูhttp://jsperf.com/startswith2/4 (ตรวจสอบให้แน่ใจว่าคุณตรวจสอบรุ่นที่ใหม่กว่าที่อาจมีการขุดของฉัน)


2

ฉันเพิ่งเรียนรู้เกี่ยวกับไลบรารีสตริงนี้:

http://stringjs.com/

รวมไฟล์ js แล้วใช้Sตัวแปรเช่นนี้:

S('hi there').endsWith('hi there')

มันยังสามารถใช้ใน NodeJS โดยติดตั้ง:

npm install string

จากนั้นกำหนดให้เป็นSตัวแปร:

var S = require('string');

หน้าเว็บยังมีลิงก์ไปยังไลบรารีสตริงทางเลือกด้วยหากหน้าเว็บนี้ไม่ใช้ความคิดของคุณ


2
  1. คำถามนั้นค่อนข้างเก่า แต่ฉันอยากจะเขียนคำตอบนี้เพื่อแสดงให้คุณเห็นถึงมาตรฐานที่ฉันได้ทำตามคำตอบทั้งหมดที่มีให้ที่นี่และ jsperf แบ่งปันโดย Jim Buck

โดยทั่วไปฉันต้องการวิธีที่รวดเร็วในการค้นหาว่าเข็มยาวอยู่ในกองหญ้ายาวและพวกมันคล้ายกันมากยกเว้นตัวละครตัวสุดท้าย

นี่คือรหัสที่ฉันเขียนซึ่งสำหรับแต่ละฟังก์ชั่น (การต่อสายย่อยการเริ่มต้นด้วย ฯลฯ ) ทดสอบทั้งสองเมื่อพวกเขาส่งคืนเท็จและเป็นจริงกับสตริงที่กองหญ้า ( nestedString) ของ 1.000.0001 ตัวอักษรและสตริงเข็มเท็จหรือความจริงของ 1,000,000 ตัวอักษร ( testParentStringFalseและtestParentStringTrueตามลำดับ):

// nestedString is made of 1.000.001 '1' repeated characters.
var nestedString = '...'

// testParentStringFalse is made of 1.000.000 characters,
// all characters are repeated '1', but the last one is '2',
// so for this string the test should return false.
var testParentStringFalse = '...'

// testParentStringTrue is made of 1.000.000 '1' repeated characters,
// so for this string the test should return true.
var testParentStringTrue = '...'

// You can make these very long strings by running the following bash command
// and edit each one as needed in your editor
// (NOTE: on OS X, `pbcopy` copies the string to the clipboard buffer,
//        on Linux, you would probably need to replace it with `xclip`):
// 
//     printf '1%.0s' {1..1000000} | pbcopy
// 

function testString() {
    let dateStart
    let dateEnd
    let avg
    let count = 100000
    const falseResults = []
    const trueResults = []

    /* slice */
    console.log('========> slice')
    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.slice(0, testParentStringFalse.length) === testParentStringFalse
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    falseResults[falseResults.length] = {
        label: 'slice',
        avg
    }
    console.log(`testString() slice = false`, res, 'avg: ' + avg + 'ms')

    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.slice(0, testParentStringTrue.length) === testParentStringTrue
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    trueResults[trueResults.length] = {
        label: 'slice',
        avg
    }
    console.log(`testString() slice = true`, res, 'avg: ' + avg + 'ms')
    console.log('<======== slice')
    console.log('')
    /* slice END */

    /* lastIndexOf */
    console.log('========> lastIndexOf')
    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.lastIndexOf(testParentStringFalse, 0) === 0
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    falseResults[falseResults.length] = {
        label: 'lastIndexOf',
        avg
    }
    console.log(`testString() lastIndexOf = false`, res, 'avg: ' + avg + 'ms')

    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.lastIndexOf(testParentStringTrue, 0) === 0
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    trueResults[trueResults.length] = {
        label: 'lastIndexOf',
        avg
    }
    console.log(`testString() lastIndexOf = true`, res, 'avg: ' + avg + 'ms')
    console.log('<======== lastIndexOf')
    console.log('')
    /* lastIndexOf END */

    /* indexOf */
    console.log('========> indexOf')
    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.indexOf(testParentStringFalse) === 0
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    falseResults[falseResults.length] = {
        label: 'indexOf',
        avg
    }
    console.log(`testString() indexOf = false`, res, 'avg: ' + avg + 'ms')

    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.indexOf(testParentStringTrue) === 0
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    trueResults[trueResults.length] = {
        label: 'indexOf',
        avg
    }
    console.log(`testString() indexOf = true`, res, 'avg: ' + avg + 'ms')
    console.log('<======== indexOf')
    console.log('')
    /* indexOf END */

    /* substring */
    console.log('========> substring')
    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.substring(0, testParentStringFalse.length) === testParentStringFalse
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    falseResults[falseResults.length] = {
        label: 'substring',
        avg
    }
    console.log(`testString() substring = false`, res, 'avg: ' + avg + 'ms')

    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.substring(0, testParentStringTrue.length) === testParentStringTrue
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    trueResults[trueResults.length] = {
        label: 'substring',
        avg
    }
    console.log(`testString() substring = true`, res, 'avg: ' + avg + 'ms')
    console.log('<======== substring')
    console.log('')
    /* substring END */

    /* startsWith */
    console.log('========> startsWith')
    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.startsWith(testParentStringFalse)
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    falseResults[falseResults.length] = {
        label: 'startsWith',
        avg
    }
    console.log(`testString() startsWith = false`, res, 'avg: ' + avg + 'ms')

    dateStart = +new Date()
    var res
    for (let j = 0; j < count; j++) {
        res = nestedString.startsWith(testParentStringTrue)
    }
    dateEnd = +new Date()
    avg = (dateEnd - dateStart)/count
    trueResults[trueResults.length] = {
        label: 'startsWith',
        avg
    }
    console.log(`testString() startsWith = true`, res, 'avg: ' + avg + 'ms')
    console.log('<======== startsWith')
    console.log('')
    /* startsWith END */

    falseResults.sort((a, b) => a.avg - b.avg)
    trueResults.sort((a, b) => a.avg - b.avg)

    console.log('false results from fastest to slowest avg:', falseResults)
    console.log('true results from fastest to slowest avg:', trueResults)
}

ฉัน runned ทดสอบมาตรฐานนี้ในChrome 75 , Firefox 67 , Safari 12และโอเปร่า 62

ฉันไม่ได้รวม Edge และ IE ไว้เพราะฉันไม่มีพวกเขาในเครื่องนี้ แต่ถ้าใครบางคนที่คุณต้องการเรียกใช้สคริปต์กับ Edge และอย่างน้อย IE 9 และแบ่งปันผลลัพธ์ที่นี่ฉันอยากรู้อยากเห็นผลลัพธ์มาก

เพียงจำไว้ว่าคุณจะต้องสร้างสตริงยาว 3 สตริงและบันทึกสคริปต์ในไฟล์ที่คุณเปิดในเบราว์เซอร์ของคุณเป็นคัดลอก / วางบนคอนโซลของเบราว์เซอร์จะบล็อกมันเนื่องจากความยาวของแต่ละสตริง>> 1.000.000)

นี่คือผลลัพธ์:

Chrome 75 ( substringชนะ):

false results from fastest to slowest avg:
1)  {"label":"substring","avg":0.08271}
2)  {"label":"slice","avg":0.08615}
3)  {"label":"lastIndexOf","avg":0.77025}
4)  {"label":"indexOf","avg":1.64375}
5)  {"label":"startsWith","avg":3.5454}

true results from fastest to slowest avg:
1)  {"label":"substring","avg":0.08213}
2)  {"label":"slice","avg":0.08342}
3)  {"label":"lastIndexOf","avg":0.7831}
4)  {"label":"indexOf","avg":0.88988}
5)  {"label":"startsWith","avg":3.55448}

Firefox 67 ( indexOfชนะ):

false results from fastest to slowest avg
1)  {"label":"indexOf","avg":0.1807}
2)  {"label":"startsWith","avg":0.74621}
3)  {"label":"substring","avg":0.74898}
4)  {"label":"slice","avg":0.78584}
5)  {"label":"lastIndexOf","avg":0.79668}

true results from fastest to slowest avg:
1)  {"label":"indexOf","avg":0.09528}
2)  {"label":"substring","avg":0.75468}
3)  {"label":"startsWith","avg":0.76717}
4)  {"label":"slice","avg":0.77222}
5)  {"label":"lastIndexOf","avg":0.80527}

Safari 12 ( sliceชนะเพื่อผลที่ผิดพลาดstartsWithชนะเพื่อผลลัพธ์ที่แท้จริงและ Safari นั้นเร็วที่สุดในแง่ของเวลาทั้งหมดในการดำเนินการทดสอบทั้งหมด):

false results from fastest to slowest avg:
1) "{\"label\":\"slice\",\"avg\":0.0362}"
2) "{\"label\":\"startsWith\",\"avg\":0.1141}"
3) "{\"label\":\"lastIndexOf\",\"avg\":0.11512}"
4) "{\"label\":\"substring\",\"avg\":0.14751}"
5) "{\"label\":\"indexOf\",\"avg\":0.23109}"

true results from fastest to slowest avg:
1) "{\"label\":\"startsWith\",\"avg\":0.11207}"
2) "{\"label\":\"lastIndexOf\",\"avg\":0.12196}"
3) "{\"label\":\"substring\",\"avg\":0.12495}"
4) "{\"label\":\"indexOf\",\"avg\":0.33667}"
5) "{\"label\":\"slice\",\"avg\":0.49923}"

Opera 62 ( substringชนะผลลัพธ์คล้ายกับ Chrome และฉันไม่แปลกใจที่ Opera ใช้ Chromium และ Blink):

false results from fastest to slowest avg:
{"label":"substring","avg":0.09321}
{"label":"slice","avg":0.09463}
{"label":"lastIndexOf","avg":0.95347}
{"label":"indexOf","avg":1.6337}
{"label":"startsWith","avg":3.61454}

true results from fastest to slowest avg:
1)  {"label":"substring","avg":0.08855}
2)  {"label":"slice","avg":0.12227}
3)  {"label":"indexOf","avg":0.79914}
4)  {"label":"lastIndexOf","avg":1.05086}
5)  {"label":"startsWith","avg":3.70808}

ปรากฎว่าทุกเบราว์เซอร์มีรายละเอียดการใช้งานของตัวเอง (นอกเหนือจาก Opera ซึ่งเป็นพื้นฐานของ Chromium และ Blink ของ Chrome)

แน่นอนการทดสอบเพิ่มเติมกับกรณีการใช้งานที่แตกต่างกันสามารถและควรจะดำเนินการ (เช่นเมื่อเข็มสั้นจริงๆเมื่อเทียบกับกองหญ้าเมื่อกองหญ้าสั้นกว่าเข็ม ฯลฯ ... ) แต่ในกรณีของฉันฉันต้องเปรียบเทียบสตริงที่ยาวมากและ ต้องการแบ่งปันที่นี่



0

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

if(typeof String.prototype.startsWith != 'function'){
    String.prototype.startsWith = function(str){
        if(str == null) return false;
        var i = str.length;
        if(this.length < i) return false;
        for(--i; (i >= 0) && (this[i] === str[i]); --i) continue;
        return i < 0;
    }
}

สิ่งนี้อิงจาก startsWith2 จากที่นี่: http://jsperf.com/startswith2/6 http://jsperf.com/startswith2/6ฉันเพิ่ม tweak เล็ก ๆ สำหรับการปรับปรุงประสิทธิภาพเล็ก ๆ และหลังจากนั้นก็เพิ่มการตรวจสอบสำหรับสตริงการเปรียบเทียบว่าเป็นโมฆะหรือไม่ได้กำหนดและแปลงมันเพื่อเพิ่มลงในต้นแบบของ String โดยใช้เทคนิคในคำตอบของ CMS

โปรดทราบว่าการใช้งานนี้ไม่สนับสนุนพารามิเตอร์ "ตำแหน่ง" ซึ่งกล่าวถึงในหน้าMozilla Developer Networkนี้ แต่ดูเหมือนจะไม่ได้เป็นส่วนหนึ่งของข้อเสนอ ECMAScript


0

ฉันไม่แน่ใจเกี่ยวกับจาวาสคริปต์ แต่ใน typescript ฉันทำสิ่งที่ชอบ

var str = "something";
(<String>str).startsWith("some");

ฉันคิดว่ามันควรจะทำงานกับ js ด้วย ฉันหวังว่ามันจะช่วย!


-2

หากคุณกำลังทำงานกับstartsWith()และendsWith()คุณจะต้องระมัดระวังเกี่ยวกับช่องว่างนำ นี่คือตัวอย่างที่สมบูรณ์:

var str1 = " Your String Value Here.!! "; // Starts & ends with spaces    
if (str1.startsWith("Your")) { }  // returns FALSE due to the leading spaces…
if (str1.endsWith("Here.!!")) { } // returns FALSE due to trailing spaces…

var str2 = str1.trim(); // Removes all spaces (and other white-space) from start and end of `str1`.
if (str2.startsWith("Your")) { }  // returns TRUE
if (str2.endsWith("Here.!!")) { } // returns TRUE

3
นี่เป็นพฤติกรรมที่ไม่ได้มาตรฐาน: สตริง "abc" ไม่ได้ขึ้นต้นด้วย "abc" โดยเฉพาะอย่างยิ่ง ECMA 6 ไม่ถือว่าการเรียงลำดับสตริงใด ๆ ดังนั้นช่องว่างต้องตรงกันอย่างแท้จริงเพื่อให้ได้การเริ่มต้นด้วยการจับคู่
Steve Hollasch

3
อะไรคือสิ่งที่ตอบคำถามนี้?
DCShannon

1
@ DCShannon ไม่ใช่ มันเป็นเรื่องไร้สาระที่เข้าใจยาก
Mark Amery

2
@SteveHollasch ความตั้งใจของฉันคือการตระหนักถึงทุกคนที่กำลังมองหาปัญหาเดียวกันที่ฉันต้องเผชิญ ว่าเราต้องระวังช่องว่างนำเมื่อทำงานกับstartsWith()และendsWith()ฟังก์ชั่น ไม่มีอะไรอีกแล้ว!
immayankmodi

-3

คุณยังสามารถส่งคืนสมาชิกทั้งหมดของอาเรย์ที่ขึ้นต้นด้วยสตริงโดยการสร้างต้นแบบ / ส่วนขยายของคุณเองไปยังอาเรย์ต้นแบบอาคา

Array.prototype.mySearch = function (target) {
    if (typeof String.prototype.startsWith != 'function') {
        String.prototype.startsWith = function (str){
        return this.slice(0, str.length) == str;
      };
    }
    var retValues = [];
    for (var i = 0; i < this.length; i++) {
        if (this[i].startsWith(target)) { retValues.push(this[i]); }
    }
    return retValues;
};

และใช้มัน:

var myArray = ['Hello', 'Helium', 'Hideout', 'Hamster'];
var myResult = myArray.mySearch('Hel');
// result -> Hello, Helium
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.