简体   繁体   English

string.match()返回String而不是Array

[英]string.match() returns a String instead of an Array

I've been using Javascript string.match(*regex*) function to parse the navigator.userAgent string. 我一直在使用Javascript string.match(*regex*)函数来解析navigator.userAgent字符串。

FYI, According to MDN & W3schools: 根据MDN和W3schools,仅供参考:

"The match() method searches a string for a match against a regular expression, and returns the matches, as an Array object ." “match()方法在字符串中搜索与正则表达式的匹配,并将匹配作为Array对象返回。”

I first parse once to get the wanted strings for the base string: 我首先解析一次以获取基本字符串所需的字符串:

var userAgent = navigator.userAgent;
var splitted = userAgent.match(/[(][^)]+[)]|\w+\/\S+/ig);

Which gives me the following Output (Which is an Array) 这给了我以下输出(这是一个数组)

Mozilla/5.0
(Macintosh; Intel Mac OS X 10_10_3)
AppleWebKit/537.36
(KHTML, like Gecko)
Chrome/41.0.2272.76
Safari/537.36

Then i parse the Navigator/Version type strings in a for loop 然后我在for循环中解析Navigator / Version类型字符串

for (var i = 0; i < splitted.length; i++ ) {
    var str = splitted[i];
    if (str[0] == '(') {
    } else {
        var name = str.match(/[^\/]+/i);
        var version = str.match(/[0-9|\.]+/i);
}

But, very surprisingly and even though I get the desired result, I get a String Object for the name and an Array Object for the version 但是,非常令人惊讶,即使我得到了所需的结果, 我得到了一个String对象的名称和一个Array对象的版本

How is it even possible ? 怎么可能呢?

Here's the snippet of the code ( fiddle ): 这是代码的片段( 小提琴 ):

 var userAgent = navigator.userAgent; var splitted = userAgent.match(/[(][^)]+[)]|\\w+\\/\\S+/ig); var outputDiv = document.getElementById("log"); for (var i = 0; i < splitted.length; i++ ) { var str = splitted[i]; if (str[0] == '(') { } else { var name = str.match(/[^\\/]+/i); var version = str.match(/[0-9|\\.]+/i); outputDiv.innerHTML += name.toString() + " is a " + typeof(name) + "<br>"; outputDiv.innerHTML += version.toString() + " is a " + typeof(version) + "<br>"; } }; 
 <div id="log"></div> 

--- UPDATE --- ---更新---

Thanks FactoryAidan for the answer, it was a scope problem. 感谢FactoryAidan的答案,这是一个范围问题。

Conclusion: be careful when naming global variables :) 结论:命名全局变量时要小心:)

Global Variable Scope 全局变量范围

It is because you are using name as your variable. 这是因为您使用name作为变量。 This is a global browser window variable that is inherently a string and cannot be stored as an Array 这是一个全局浏览器窗口变量,本质上是一个字符串,不能存储为数组

Even if you redeclare it with var name = , you are still in the global scope. 即使您使用var name =重新声明它,您仍然在全局范围内。 And thus name (aka window.name ) simply retains the last value you assign to it. 因此, name (aka window.name )只保留您为其分配的最后一个值。

You can test this with the following on an empty page without defining any variables at all: 您可以在空白页面上使用以下内容对此进行测试,而无需定义任何变量:

console.log(name===window.name) // Returns true
console.log(name,window.name)   // Returns 'Safari Safari' for my browser

Change name to something else name更改为其他name

If you change your name variable to simply have a different name, like my_name , it stores the result of .match() as an Array. 如果将name变量更改为只是具有不同的名称(如my_name ,则会将.match()的结果存储为Array。

var my_name = str.match(/[^\/]+/i);
var version = str.match(/[0-9|\.]+/i);

console.log(typeof my_name, my_name instanceof Array) // Returns object, true

Change Scope by wrapping in a function 通过包装在函数中来更改范围

This is your exact code wrapped inside a function and returns the correct variable types: 这是包含在函数内的确切代码,并返回正确的变量类型:

function getBrowserStuff(){

    var userAgent = navigator.userAgent;
    var splitted = userAgent.match(/[(][^)]+[)]|\w+\/\S+/ig);

    for (var i = 0; i < splitted.length; i++ ) {
        var str = splitted[i];
        if (str[0] == '(') {
        } else {
            var name = str.match(/[^\/]+/i);
            var version = str.match(/[0-9|\.]+/i);
            console.log('Name','Typeof '+(typeof name), 'IsArray '+(name instanceof Array),name)
            console.log('Version','Typeof '+(typeof version),'IsArray '+(version instanceof Array),version)
        }
    }

    return 'whatever'
}

getBrowserStuff()

Changing the variable name to my_name OR wrapping code like the above function returns this: 将变量name更改为my_name 包装代码,如上面的函数返回:

Name    Typeof object IsArray true ["Mozilla"]
Version Typeof object IsArray true ["5.0"]
Name    Typeof object IsArray true ["AppleWebKit"]
Version Typeof object IsArray true ["600.3.18"]
Name    Typeof object IsArray true ["Version"]
Version Typeof object IsArray true ["8.0.3"]
Name    Typeof object IsArray true ["Safari"]
Version Typeof object IsArray true ["600.3.18"]

Where before it returned this: 之前它返回的地方:

Name    Typeof string IsArray false Mozilla
Version Typeof object IsArray true  ["5.0"]
Name    Typeof string IsArray false AppleWebKit
Version Typeof object IsArray true  ["600.3.18"]
Name    Typeof string IsArray false Version
Version Typeof object IsArray true  ["8.0.3"]
Name    Typeof string IsArray false Safari
Version Typeof object IsArray true  ["600.3.18"]

This is not possible, or is a bug of your implementation. 这是不可能的,或者是您实施的错误。

According to the ECMAScript 5.1 specification, match behaves like this: 根据ECMAScript 5.1规范, match行为如下:

15.5.4.10 String.prototype.match (regexp) 15.5.4.10 String.prototype.match(regexp)

When the match method is called with argument regexp , the following steps are taken: 使用参数regexp调用match方法时,将执行以下步骤:

  1. Call CheckObjectCoercible passing the this value as its argument. 调用CheckObjectCoercible将此值作为参数传递。
  2. Let S be the result of calling ToString , giving it the this value as its argument. S是调用ToString的结果,给它作为参数的值。
  3. If Type ( regexp ) is Object and the value of the [[Class]] internal property of regexp is " RegExp ", then let rx be regexp ; 如果类型正则表达式 )是Object和的值[[类]] 正则表达式的内部属性是“ RegExp ”,则设RX正则表达式 ;
  4. Else, let rx be a new RegExp object created as if by the expression new RegExp( regexp ) where RegExp is the standard built-in constructor with that name. 另外,让rx成为一个新的RegExp对象,就像表达式new RegExp( regexp ) ,其中RegExp是具有该名称的标准内置构造函数。
  5. Let global be the result of calling the [[Get]] internal method of rx with argument " global ". global成为使用参数“ global ”调用rx的[[Get]]内部方法的结果。
  6. Let exec be the standard built-in function RegExp.prototype.exec ( see 15.10.6.2 ) exec成为标准的内置函数RegExp.prototype.exec见15.10.6.2
  7. If global is not true , then 如果全球正确 ,那么
    1. Return the result of calling the [[Call]] internal method of exec with rx as the this value and argument list containing S . 返回使用rx调用exec的[[Call]]内部方法的结果作为包含S值和参数列表。
  8. Else, global is true 否则, 全球化真的
    1. Call the [[Put]] internal method of rx with arguments " lastIndex " and 0. 使用参数“ lastIndex ”和0调用rx的[[Put]]内部方法。
    2. Let A be a new array created as if by the expression new Array() where Array is the standard built-in constructor with that name. A是一个新的数组,就像表达式new Array() ,其中Array是具有该名称的标准内置构造函数。
    3. Let previousLastIndex be 0. previousLastIndex为0。
    4. Let n be 0. n为0。
    5. Let lastMatch be true . lastMatch成为现实
    6. Repeat, while lastMatch is true 重复,而lastMatchtrue
      1. Let resul t be the result of calling the [[Call]] internal method of exec with rx as the this value and argument list containing S . resul吨是调用exec的[[调用]]内部方法与RX为包含S中的值和参数列表的结果。
      2. If result is null , then set lastMatch to false . 如果resultnull ,则将lastMatch设置为false
      3. Else, result is not null 否则, 结果不为
        1. Let thisIndex be the result of calling the [[Get]] internal method of rx with argument " lastIndex ". thisIndex是使用参数“ lastIndex ”调用rx的[[Get]]内部方法的结果。
        2. If thisIndex = previousLastIndex then 如果thisIndex = previousLastIndex
          1. Call the [[Put]] internal method of rx with arguments " lastIndex " and thisIndex +1. 使用参数“ lastIndex ”和thisIndex +1调用rx的[[Put]]内部方法。
          2. Set previousLastIndex to thisIndex +1. previousLastIndex设置为thisIndex +1。
        3. Else, set previousLastIndex to thisIndex . 否则,将previousLastIndex设置为thisIndex
        4. Let matchStr be the result of calling the [[Get]] internal method of result with argument " 0 ". matchStr是用参数“ 0 ”调用结果的[[Get]]内部方法的结果
        5. Call the [[DefineOwnProperty]] internal method of A with arguments ToString ( n ), the Property Descriptor {[[Value]]: matchStr , [[Writable]]: true , [[Enumerable]]: true , [[configurable]]: true }, and false . A的[[DefineOwnProperty]]内部方法与参数的ToString (n)时, 属性描述符 {[[价值]]: 和matchstr,[可写]]: ,[可枚举]]: ,[[配置] ]: true }, false
        6. Increment n . 增量ñ。
    7. If n = 0, then return null . 如果n = 0,则返回null
    8. Return A . 返回A.

Therefore, for your global regex, the only possible returned values are null or A , which is an array. 因此,对于全局正则表达式,唯一可能的返回值为nullA ,即数组。

For the non global ones, the result of calling RegExp.prototype.exec is returned. 对于非全局的,返回调用RegExp.prototype.exec的结果。 But it also returns an array or null : 但它也返回一个数组或null

Performs a regular expression match of string against the regular expression and returns an Array object containing the results of the match, or null if string did not match. 对正则表达式执行字符串的正则表达式匹配,并返回包含匹配结果的Array对象,如果字符串不匹配,则返回null

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM