Làm thế nào để kiểm tra xem một chuỗi Star StartsWith có chuỗi khác không?


1690

Làm cách nào để tôi viết tương đương với C # String.StartsWithtrong JavaScript?

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

haystack.startsWith(needle) == true

Lưu ý: Đây là một câu hỏi cũ và như đã nêu trong các nhận xét ECMAScript 2015 (ES6) đã giới thiệu .startsWithphương pháp này. Tuy nhiên, tại thời điểm viết bản cập nhật này (2015), hỗ trợ trình duyệt vẫn chưa hoàn tất .

Câu trả lời:


1773

Bạn có thể sử dụng String.prototype.startsWith()phương pháp của ECMAScript 6 , nhưng nó chưa được hỗ trợ trong tất cả các trình duyệt . Bạn sẽ muốn sử dụng shim / polyfill để thêm nó trên các trình duyệt không hỗ trợ nó. Tạo một triển khai tuân thủ tất cả các chi tiết được nêu trong thông số kỹ thuật là một chút phức tạp. Nếu bạn muốn một shim trung thành, sử dụng một trong hai:

Khi bạn đã sử dụng phương thức này (hoặc nếu bạn chỉ hỗ trợ các trình duyệt và công cụ JavaScript đã có), bạn có thể sử dụng phương thức này như sau:

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

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

@gtournie tại sao lại bắt đầuVới một trong những phương pháp tồi tệ nhất để kiểm tra nếu một chuỗi bắt đầu bằng một chuỗi? (xem bình luận của bạn ở đây: stackoverflow.com/questions/646628/ mài ) bạn nhiệt tình hơn trong việc so sánh các ký tự cho mỗi ký tự. Tôi hy vọng trình biên dịch đủ thông minh KHÔNG tạo ra một chuỗi cho mỗi chuỗi [index] bởi vì, nếu bạn chỉ đơn giản viết cái này: character = string [0] thì nó sẽ cấp phát một đối tượng, vô cùng LESS hiệu quả hơn so với việc sử dụng startedWith (startedWith sẽ không phân bổ bất kỳ bộ nhớ nào )
Martijn Scheffer

@MartijnScheffer: Câu trả lời đã được chỉnh sửa nhiều lần kể từ khi tôi trả lời và bây giờ hoàn toàn khác (tôi đã xóa nhận xét của mình;). Tôi đồng ý rằng phương thức startWith của ECMAScript 6 là cách tốt nhất để làm điều đó.
gtournie

6
@GrahamLaight, khi bạn nói được hỗ trợ bởi 'IE', có lẽ bạn có nghĩa là Edge. developer.mozilla.org/en/docs/Web/JavaScript/Reference/
Kẻ

@Marcus, xin lỗi nếu tôi sai - thông tin của tôi đến từ: w3schools.com/jsref/jsref_startswith.asp
Graham Laight

CẢNH BÁO! Các bài kiểm tra jsperf này không hoạt động trong các trình duyệt giỏi biên dịch JIT. Các trình duyệt như Firefox và Chrome đôi khi nhận ra nó khi kết quả của một thao tác bị loại bỏ và do đó không thực hiện thao tác đó . Ngoài ra, các công cụ javascript hiện đại sử dụng dự đoán nhánh , do đó, các chuỗi thử nghiệm phải khác nhau trong mỗi lần lặp.
Aloso

1283

Một cách khác với .lastIndexOf:

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

Điều này nhìn ngược lại haystackcho sự xuất hiện needlebắt đầu từ chỉ số 0của haystack. Nói cách khác, nó chỉ kiểm tra nếu haystackbắt đầu bằng needle.

Về nguyên tắc, điều này sẽ có lợi thế về hiệu suất so với một số phương pháp khác:

  • Nó không tìm kiếm toàn bộ haystack.
  • Nó không tạo ra một chuỗi tạm thời mới và sau đó loại bỏ nó ngay lập tức.

1
Không chắc chắn trường hợp nào @ rfcoder89 đang diễn ra - jsfiddle.net/jkzjw3w2/1
Gulfaraz Rahman

5
@ rfcoder89 Lưu ý tham số thứ hai của lastIndexOf: "aba".lastIndexOf ("a")là 2 như bạn chỉ ra, nhưng "aba".lastIndexOf ("a", 0)là 0, đúng
maxpolk

1
Cảm ơn bạn rất nhiều. String.startsWith không hoạt động trên WebView kẹo mút Android, nhưng đoạn mã cuối cùng IndexOf này thì có !!!
Herman

với lastIndexOf , chuỗi được tìm kiếm từ đầu đến đầu để nó tìm kiếm toàn bộ chuỗi: vì vậy, sự kém hiệu quả của nó tăng lên cho các chuỗi rất dài để tìm kiếm.
willy wonka

8
@willywonka Không, không phải nếu bạn có 0 start Index, nó được tìm kiếm từ 0 pos và đó là kiểm tra duy nhất. Toàn bộ chuỗi chỉ được tìm kiếm nếu from Index> = str.length.
greene

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

3
@ANeves Tôi nghi ngờ nó phụ thuộc nhiều vào trình duyệt và dữ liệu được sử dụng. Xem câu trả lời của Ben Weaver cho các phép đo thực tế. Trên trình duyệt tôi đang chạy (Chrome 12.0.742 trên Windows), chuỗi con chiến thắng để thành công và chiến thắng regex được chuẩn bị cho thất bại.
cobbal

4
@cobbal Có lẽ. Nhưng .lastIndexOf(input, 0)so sánh các ký tự N đầu tiên, trong khi .substring(0, input.length) === inputđếm N, nối các dữ liệu với độ dài N và sau đó so sánh các ký tự N đó. Trừ khi có tối ưu hóa mã, phiên bản thứ hai này không thể nhanh hơn phiên bản kia. Đừng hiểu lầm tôi, tôi sẽ không bao giờ tự mình tìm thấy thứ gì đó tốt hơn bạn đề xuất. :)
ANeves

2
@ANeves Nhưng .lastIndexOf trên một chuỗi dài sẽ trả về false sẽ lặp lại trên toàn bộ chuỗi (O (N)), trong khi trường hợp .sub chuỗi lặp lại trên một chuỗi có khả năng nhỏ hơn nhiều. Nếu bạn mong đợi thành công đa số hoặc chỉ đầu vào nhỏ, .lastIndexOf có khả năng nhanh hơn - nếu không .sub chuỗi có thể nhanh hơn. .sub chuỗi cũng có nguy cơ ngoại lệ nếu đầu vào dài hơn chuỗi được kiểm tra.
Chris Moschini

14
@ChrisMoschini, đừng quên rằng giải pháp của Mark Byers đã lastIndexOfbắt đầu ở chỉ số 0, không phải kết thúc. Điều đó làm tôi vấp ngã, ban đầu, quá. Tuy nhiên, việc kiểm tra chuỗi bắt đầu bằng một nhiệm vụ phổ biến đến mức JavaScript thực sự phải có API phù hợp cho nó, không phải tất cả các thành ngữ và các lựa chọn thay thế bạn thấy trên trang này, tuy nhiên chúng rất thông minh.
Randall Cook

4
Tôi thích giải pháp của cobbal hơn Mark. Ngay cả khi nhãn hiệu nhanh hơn và một mẹo ấn tượng khi sử dụng thông số, nó rất khó đọc so với chuỗi con.
ThinkBonobo

184

Không có chức năng trợ giúp, chỉ cần sử dụng .testphương thức của regex :

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

Để thực hiện điều này với một chuỗi động chứ không phải là mã hóa cứng (giả sử rằng chuỗi đó sẽ không chứa bất kỳ ký tự điều khiển regrec nào):

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

Bạn nên kiểm tra Có chức năng RegExp.escape trong Javascript không? nếu khả năng tồn tại mà các ký tự điều khiển regrec xuất hiện trong chuỗi.


1
Để sử dụng biểu thức phân biệt chữ hoa chữ thường/^he/i
kaizer1v

64

Giải pháp tốt nhất:

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

Và đây là kết thúc với nếu bạn cũng cần điều đó:

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

Đối với những người thích nguyên mẫu nó thành Chuỗi:

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

Sử dụng:

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

Với phương pháp:

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

Tôi nghĩ rằng bạn đã trộn lẫn Last IndexOf và indexOf trong các chức năng của mình - startedWith sẽ được trả về str.indexOf (word, 0) === 0;
Richard Matheson

5
@RichardMatheson vấn đề với việc sử dụng indexOf là nếu nó không khớp khi bắt đầu, nó sẽ tiếp tục tìm kiếm toàn bộ chuỗi, theo đó, Last IndexOf bắt đầu từ độ dài của từ và trở về 0. Hiểu rồi?
mmm

2
À đúng rồi, bây giờ tôi không chú ý đến các chỉ số bạn đang sử dụng. Thủ thuật rất hay!
Richard Matheson

54

Tôi chỉ muốn thêm ý kiến ​​của tôi về điều này.

Tôi nghĩ rằng chúng ta có thể sử dụng như thế này:

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

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

2
Câu trả lời của Mark Byers được so sánh về hiệu suất của ba cách tiếp cận đúng khác nhau của @relfor. Cách tiếp cận đúng này không được ưa chuộng vì nó yêu cầu tìm kiếm toàn bộ chuỗi.
maxpolk

@maxpolk Tôi nghĩ indexOfsẽ ngừng tìm kiếm toàn bộ chuỗi khi nó tìm thấy lần đầu tiên. Tôi đã kiểm tra nó.
Mr.D

8
Nếu sự xuất hiện đầu tiên không được tìm thấy ngay từ đầu, cách tiếp cận này bắt đầu phát triển không hiệu quả khi nó tiếp tục tìm kiếm nó, có khả năng tìm kiếm cho đến khi kết thúc, thay vì từ bỏ sớm hơn nhiều. Bởi vì có một tiềm năng cho sự kém hiệu quả, nó không được ưa chuộng trong số ba cách tiếp cận đúng.
maxpolk

2
@ Mr.D Và nếu không có trận đấu?
mmm

khác khi tất cả các đống cỏ khô đã được tìm kiếm? là tốt hơn: stackoverflow.com/a/36876507/961018 .. chỉ tìm kiếm tối đa từ
mmm

39

Đây là một cải tiến nhỏ cho giải pháp của 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

Kiểm tra xem hàm đã tồn tại trong trường hợp trình duyệt trong tương lai thực hiện nó trong mã gốc hay nếu nó được thư viện khác triển khai. Ví dụ, Thư viện Nguyên mẫu đã thực hiện chức năng này.

Sử dụng !là hơi nhanh hơn và ngắn gọn hơn === 0mặc dù không thể đọc được.


1
Điều này có thể trở thành một vấn đề: Nếu việc triển khai đã diễn ra khác với chính tôi thì điều này sẽ phá vỡ ứng dụng của tôi.
Christoph Wurm

2
Điều này có vấn đề O (N) được thảo luận ở đây stackoverflow.com/questions/646628/javascript-startswith/iêu
Chris Moschini

1
sử dụng! có rất lộn xộn
JonnyRaa

-1; thêm điều này vào String.prototypelà một ý tưởng tồi bởi vì nó không đến bất cứ nơi nào gần với việc tuân thủ thông số kỹ thuật cho String.prototype.startsWith. Bất kỳ mã nào cố gắng sử dụng phương pháp ES6 đều có thể bị lỗi nếu bạn đang làm điều này; nó cũng có thể xem liệu phương thức đã được xác định chưa, xem nó là (xấu, bởi bạn) và không thêm vào một shim tuân thủ thông số kỹ thuật, dẫn đến hành vi không chính xác sau này.
Đánh dấu Amery

21

Ngoài ra, hãy kiểm tra underscore.opes.js . Nó đi kèm với một loạt các phương pháp kiểm tra và thao tác chuỗi hữu ích, bao gồm cả một startsWithphương thức. Từ các tài liệu:

bắt đầu với _.startsWith(string, starts)

Phương pháp này kiểm tra xem stringbắt đầu bằng starts.

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

1
Tôi cần_.string.startsWith
Đại tá Panic

15

Gần đây tôi đã tự hỏi mình câu hỏi tương tự.
Có nhiều giải pháp khả thi, đây là 3 giải pháp hợp lệ:

  • s.indexOf(starter) === 0
  • s.substr(0,starter.length) === starter
  • s.lastIndexOf(starter, 0) === 0(được thêm vào sau khi thấy câu trả lời của Mark Byers )
  • sử dụng một vòng lặp:

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

Tôi đã không đi qua giải pháp cuối cùng sử dụng một vòng lặp.
Đáng ngạc nhiên là giải pháp này vượt trội so với 3 đầu tiên bởi một tỷ lệ đáng kể.
Dưới đây là bài kiểm tra jsperf tôi đã thực hiện để đi đến kết luận này: http://jsperf.com/startswith2/2

Sự thanh bình

ps: ecmascript 6 (hòa âm) giới thiệu một startsWithphương thức riêng cho chuỗi.
Chỉ cần nghĩ rằng sẽ tiết kiệm được bao nhiêu thời gian nếu họ nghĩ đến việc đưa phương thức rất cần thiết này vào chính phiên bản ban đầu.

Cập nhật

Như Steve đã chỉ ra (nhận xét đầu tiên về câu trả lời này), hàm tùy chỉnh ở trên sẽ đưa ra lỗi nếu tiền tố đã cho ngắn hơn toàn bộ chuỗi. Ông đã sửa lỗi đó và thêm một tối ưu hóa vòng lặp có thể được xem tại http://jsperf.com/startswith2/4 .

Lưu ý rằng có 2 tối ưu hóa vòng lặp mà Steve đưa vào, lần đầu tiên trong hai lần này cho thấy hiệu suất tốt hơn, do đó tôi sẽ đăng đoạn mã dưới đây:

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

Xem rev mới nhất. Bên cạnh lỗi trong phiên bản trên (nó sẽ ném nếu chuỗi ngắn hơn tiền tố), nó cũng chậm hơn phiên bản được tối ưu hóa hơn. Xem jsperf.com/startswith2/4jsperf.com/js-startswith353 .
Steve Hollasch

^ Cảm ơn bạn đã chỉ ra trường hợp chuỗi ngắn hơn tiền tố
Raj Nathani

jsperf.com/startswith2/29 => startsWith5 là súc tích và thực hiện rất tốt =)
gtournie

11

Vì nó rất phổ biến nên tôi nghĩ rằng đáng để chỉ ra rằng có một triển khai cho phương pháp này trong ECMA 6 và để chuẩn bị cho việc đó, người ta nên sử dụng polyfill 'chính thức' để ngăn chặn các vấn đề và nước mắt trong tương lai.

May mắn thay, các chuyên gia tại Mozilla cung cấp cho chúng tôi một:

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

Xin lưu ý rằng điều này có lợi thế là bị bỏ qua một cách duyên dáng khi chuyển sang ECMA 6.


5

Giải pháp hiệu quả tốt nhất là ngừng sử dụng các cuộc gọi thư viện và chỉ nhận ra rằng bạn đang làm việc với hai mảng. Việc triển khai bằng tay vừa ngắn vừa nhanh hơn mọi giải pháp khác tôi từng thấy ở đây.

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

Để so sánh hiệu suất (thành công và thất bại), xem http://jsperf.com/startswith2/4 . (Hãy chắc chắn rằng bạn kiểm tra các phiên bản mới hơn có thể đã bị lỗi của tôi.)


2

Tôi vừa tìm hiểu về thư viện chuỗi này:

http://opesjs.com/

Bao gồm tệp js và sau đó sử dụng Sbiến như thế này:

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

Nó cũng có thể được sử dụng trong NodeJS bằng cách cài đặt nó:

npm install string

Sau đó yêu cầu nó là Sbiến:

var S = require('string');

Trang web cũng có các liên kết đến các thư viện chuỗi thay thế, nếu thư viện này không thích bạn.


2
  1. Câu hỏi hơi cũ, nhưng tôi muốn viết câu trả lời này để cho bạn thấy một số điểm chuẩn tôi đã thực hiện dựa trên tất cả các câu trả lời được cung cấp ở đây và jsperf được chia sẻ bởi Jim Buck.

Về cơ bản tôi cần một cách nhanh chóng để tìm xem một cây kim dài có nằm trong đống cỏ dài hay không và chúng rất giống nhau ngoại trừ các ký tự cuối cùng.

Đây là mã tôi đã viết, cho mỗi hàm (splice, chuỗi con, startedWith, v.v.) kiểm tra cả khi chúng trả về false và true đối với chuỗi haystack ( nestedString) 1.000.0001 ký tự và chuỗi kim sai lệch hoặc trung thực là 1.000.000 ký tự ( testParentStringFalsetestParentStringTrue, tương ứng):

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

Tôi đã chạy thử nghiệm điểm chuẩn này trên Chrome 75 , Firefox 67 , Safari 12Opera 62 .

Tôi chưa bao gồm Edge và IE vì tôi không có chúng trên máy này, nhưng nếu ai đó trong số bạn muốn chạy tập lệnh với Edge và ít nhất là IE 9 và chia sẻ đầu ra ở đây, tôi sẽ rất tò mò muốn xem kết quả.

Chỉ cần nhớ rằng bạn cần tạo lại 3 chuỗi dài và lưu tập lệnh trong tệp mà sau đó bạn mở trong trình duyệt của mình dưới dạng sao chép / dán trên bảng điều khiển của trình duyệt sẽ chặn chuỗi vì mỗi độ dài của chuỗi là> = 1.000.000).

Dưới đây là kết quả đầu ra:

Chrome 75 ( substringthắng):

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 ( indexOfthắng):

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 ( slicechiến thắng cho kết quả sai, startsWithchiến thắng cho kết quả thực, còn Safari là nhanh nhất về tổng thời gian thực hiện toàn bộ bài kiểm tra):

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 ( substringthắng. Kết quả tương tự với Chrome và tôi không ngạc nhiên vì Opera dựa trên Chromium và 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}

Hóa ra mỗi trình duyệt đều có chi tiết triển khai riêng (ngoài Opera, dựa trên Chromium và Blink của Chrome).

Tất nhiên, thử nghiệm thêm với các trường hợp sử dụng khác nhau có thể và nên được thực hiện (ví dụ: khi kim thực sự ngắn so với haystack, khi haystack ngắn hơn kim, v.v ...), nhưng trong trường hợp của tôi, tôi cần so sánh các chuỗi rất dài và muốn chia sẻ nó ở đây.


1
var str = 'hol';
var data = 'hola mundo';
if (data.length >= str.length && data.substring(0, str.length) == str)
    return true;
else
    return false;

0

Dựa trên các câu trả lời ở đây, đây là phiên bản tôi hiện đang sử dụng, vì nó dường như mang lại hiệu suất tốt nhất dựa trên thử nghiệm của JSPerf (và hoàn thành về mặt chức năng theo như tôi có thể nói).

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

Điều này được dựa trên startedWith2 từ đây: http://jsperf.com/startswith2/6 . Tôi đã thêm một tinh chỉnh nhỏ để cải thiện hiệu suất nhỏ và từ đó cũng đã thêm một kiểm tra cho chuỗi so sánh là null hoặc không xác định, và chuyển đổi nó để thêm vào nguyên mẫu Chuỗi bằng cách sử dụng kỹ thuật trong câu trả lời của CMS.

Lưu ý rằng việc triển khai này không hỗ trợ tham số "vị trí" được đề cập trong trang Mạng của Nhà phát triển Mozilla này, nhưng dường như đó không phải là một phần của đề xuất ECMAScript.


0

Tôi không chắc chắn về javascript nhưng trong bản đánh máy tôi đã làm một cái gì đó như

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

Tôi đoán nó cũng nên làm việc trên js. Tôi hy vọng nó sẽ giúp!


-2

Nếu bạn đang làm việc với startsWith()endsWith()sau đó bạn phải cẩn thận về không gian hàng đầu. Dưới đây là một ví dụ hoàn chỉnh:

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
Đây là hành vi rất không chuẩn: chuỗi "abc" KHÔNG bắt đầu bằng "abc". Cụ thể hơn, ECMA 6 không giả định bất kỳ loại cắt xén chuỗi nào, do đó, khoảng trắng phải khớp chính xác để mang lại kết quả bắt đầu.
Steve Hollasch

3
Cái gì ... làm thế nào đây là trả lời câu hỏi?
DCShannon

1
@DCShannon thì không. Nó vô nghĩa không thể hiểu được.
Đánh dấu Amery

2
@SteveHollasch Ý định của tôi là nhận ra bất cứ ai đang tìm kiếm vấn đề tương tự mà tôi gặp phải. Rằng chúng ta cần cẩn thận với không gian hàng đầu khi làm việc startsWith()và các endsWith()chức năng. Không có gì khác!
Immayankmodi 5/11/2015

-3

Bạn cũng có thể trả về tất cả các thành viên của một mảng bắt đầu bằng một chuỗi bằng cách tạo nguyên mẫu / phần mở rộng của riêng bạn cho nguyên mẫu mảng, hay còn gọi là

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

Và để sử dụng nó:

var myArray = ['Hello', 'Helium', 'Hideout', 'Hamster'];
var myResult = myArray.mySearch('Hel');
// result -> Hello, Helium
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.