JavaScript コードを記述するときは、変数やリテラルの型を決定する必要があることがよくあります。typeof、instanceof、Array.isArray() などのメソッドを使用できます。最も便利で最も便利ですか? 実用的で最も心配がありませんか?この記事では、この問題について説明します。
1. typeof
1.1 構文
typeof は、未計算の操作 Number 型を表す文字列を返します。
構文: typeof(operand) | typeof operand
パラメータ: 返される型のオブジェクトまたはプリミティブ値を表す式
説明: typeof が返される可能性があります値は次のとおりです。
[関連コースの推奨事項: JavaScript ビデオ チュートリアル ]
Type Result
Undefined“undefined” Null“object” Boolean“boolean” Number“number” Bigint“bigint” String“string” Symbol“symbol”
Host オブジェクト ( JS 環境) 特定の実装に依存します。
関数オブジェクト「関数」
その他のオブジェクト「オブジェクト」
定義と説明の観点から、この構文は次のことを決定できます。データ型はたくさんありますが、よく見ると typeof null は実際には "object" を返します。これは混乱を招きます。詳しくは後述します。最初にこの効果を見てみましょう:
// 数值 console.log(typeof 37) // number console.log(typeof 3.14) // number console.log(typeof(42)) // number console.log(typeof Math.LN2) // number console.log(typeof Infinity) // number console.log(typeof NaN) // number 尽管它是Not-A-Number的缩写,实际NaN是数字计算得到的结果,或者将其他类型变量转化成数字失败的结果 console.log(Number(1)) //number Number(1)构造函数会把参数解析成字面量 console.log(typeof 42n) //bigint // 字符串 console.log(typeof '') //string console.log(typeof 'boo') // string console.log(typeof `template literal`) // string console.log(typeof '1') //string 内容为数字的字符串仍然是字符串 console.log(typeof(typeof 1)) //string,typeof总是返回一个字符串 console.log(typeof String(1)) //string String将任意值转换成字符串 // 布尔值 console.log(typeof true) // boolean console.log(typeof false) // boolean console.log(typeof Boolean(1)) // boolean Boolean会基于参数是真值还是虚值进行转换 console.log(typeof !!(1)) // boolean 两次调用!!操作想短语Boolean() // Undefined console.log(typeof undefined) // undefined console.log(typeof declaredButUndefinedVariabl) // 未赋值的变量返回undefined console.log(typeof undeclaredVariable ) // 未定义的变量返回undefined // 对象 console.log(typeof {a: 1}) //object console.log(typeof new Date()) //object console.log(typeof /s/) // 正则表达式返回object // 下面的例子令人迷惑,非常危险,没有用处,应避免使用,new操作符返回的实例都是对象 console.log(typeof new Boolean(true)) // object console.log(typeof new Number(1)) // object console.log(typeof new String('abc')) // object // 函数 console.log(typeof function () {}) // function console.log(typeof class C { }) // function console.log(typeof Math.sin) // function
1.2謎の null
javascript の誕生以来、typeof null は常に 'object' を返します。これは、JavaScript の値が 2 つの部分で構成されているためです。1 つは型を表すラベルであり、他の部分は実際の値を表します。オブジェクト型の値型ラベルは 0 です。残念ながら、null は null ポインタを表し、その型ラベルも 0 になるように設計されているため、この typeof null === 'object'、'悪魔の子' が存在します。 。
typeof null が「null」を返すことを許可する ECMAScript の提案がありましたが、提案は拒否されました。
1.3 新しい演算子を使用します。
Function を除くすべてのコンストラクターの型は、次のように 'object' です。
var str = new String('String'); var num = new Number(100) console.log(typeof str) // object console.log(typeof num) // object var func = new Function() console.log(typeof func) // function
1.4文法における括弧の優先順位
typeof 演算は " " 演算よりも高いですが、括弧よりは低くなります
var iData = 99 console.log(typeof iData + ' Wisen') // number Wisen console.log(typeof (iData + 'Wisen')) // string
1.5 正規表現の互換性の決定
typeof /s/ === 'function'; // Chrome 1-12 , 不符合 ECMAScript 5.1 typeof /s/ === 'object'; // Firefox 5+ , 符合 ECMAScript 5.1
1.6 エラー
ECMAScript 2015 より前では、typeof は、宣言されていない場合でも、指定されたオペランドの文字列を返すことが常に保証されていました。 、typeof は未定義を返すこともできます。つまり、typeof を使用してもエラーは報告されません。
しかし、ブロックレベルのスコープと let および const コマンドが ES6 に追加された後、変数宣言の前に let および const によって宣言された変数を使用すると、ReferenceError エラーがスローされます。ブロックの先頭と変数の宣言の間には「一時的なデッドゾーン」があり、この期間中に変数にアクセスするとエラーがスローされます。次のとおりです:
console.log(typeof undeclaredVariable) // 'undefined' console.log(typeof newLetVariable) // ReferenceError console.log(typeof newConstVariable) // ReferenceError console.log(typeof newClass) // ReferenceError let newLetVariable const newConstVariable = 'hello' class newClass{}
1.7 例外
現在、すべてのブラウザは、タイプが未定義の非標準のホスト オブジェクト document.all を公開しています。 document.all のタイプ === '未定義'。ランドスケープ仕様では、非標準の外部オブジェクトに対してカスタム タイプ タグを使用できます。必要なのは、これらのタイプ タグが既存のものと異なることのみです。未定義の document.all タイプ タグの例は、元の ECMA JavaScript 標準の「意図的な違反」として分類されます。 「Web フィールド。侵害」はブラウザのいたずらである可能性があります。
概要: typeof は、変数または値の型ラベルを返します。ほとんどの型に対して正しい結果を返すことができますが、null、コンストラクター インスタンス、および正規表現には理想的ではありません。
2.instanceof
2.1 構文
instanceof 演算子は、インスタンス オブジェクト (パラメーター) のプロトタイプ チェーンを検出するために使用されます。 ) コンストラクターのプロトタイプが表示されるかどうか。
構文: オブジェクト インスタンスオブ コンストラクター
パラメータ: オブジェクト インスタンス オブジェクト
コンストラクター コンストラクター関数
説明: コンストラクター When を検出するために、instanceof 演算子が使用されます。プロパティはパラメータ オブジェクトのプロトタイプ チェーン上に存在します。
// 定义构造函数 function C() { } function D() { } var o = new C() console.log(o instanceof C) //true,因为Object.getPrototypeOf(0) === C.prototype console.log(o instanceof D) //false,D.prototype不在o的原型链上 console.log(o instanceof Object) //true 同上 C.prototype = {} var o2 = new C() console.log(o2 instanceof C) // true console.log(o instanceof C) // false C.prototype指向了一个空对象,这个空对象不在o的原型链上 D.prototype = new C() // 继承 var o3 = new D() console.log(o3 instanceof D) // true console.log(o3 instanceof C) // true C.prototype现在在o3的原型链上
式 obj instanceof Foo が true を返した場合、式が常に true を返すという意味ではなく、Foo.prototype 属性の値が変更される可能性があることに注意してください。変更された値 obj のプロトタイプ チェーン上にない可能性があり、その場合、式の値は false になります。もう 1 つの状況は、obj のプロトタイプ チェーンを変更することです。現在の ES 仕様では、オブジェクトのプロトタイプは読み取りのみで変更できませんが、非標準の __proto__ 擬似属性を使用して変更できます。 obj.__proto__ = {} を実行すると、obj instanceof Foo は false を返します。さらに、ES6 の Object.setPrototypeOf() および Reflect.setPrototypeOf() は、オブジェクトのプロトタイプを変更できます。
インスタンスと複数のグローバル オブジェクト (複数の iframe または複数のウィンドウ間の対話)
ブラウザでは、JavaScript スクリプトが複数のウィンドウ間で対話する必要がある場合があります。複数のウィンドウは複数のグローバル環境を意味し、異なるグローバル環境には異なるグローバル オブジェクトが存在するため、異なる組み込みコンストラクターが存在します。これにより、いくつかの問題が発生する可能性があります。たとえば、式 []instanceofwindow.frames[0].Array は、
であるため false を返します。Array.prototype !== window.frames[0].Array.prototype。
起初,这样可能没有意义,但是当在脚本中处理多个frame或多个window以及通过函数将对象从一个窗口传递到另一个窗口时,这就是一个非常有意义的话题。实际上,可以通过Array.isArray(myObj)或者Object.prototype.toString.call(myObj) = "[object Array]"来安全的检测传过来的对象是否是一个数组。
2.2 示例
String对象和Date对象都属于Object类型(它们都由Object派生出来)。
但是,使用对象文字符号创建的对象在这里是一个例外,虽然原型未定义,但是instanceof of Object返回true。
var simpleStr = "This is a simple string"; var myString = new String(); var newStr = new String("String created with constructor"); var myDate = new Date(); var myObj = {}; var myNonObj = Object.create(null); console.log(simpleStr instanceof String); // 返回 false,虽然String.prototype在simpleStr的原型链上,但是后者是字面量,不是对象 console.log(myString instanceof String); // 返回 true console.log(newStr instanceof String); // 返回 true console.log(myString instanceof Object); // 返回 true console.log(myObj instanceof Object); // 返回 true, 尽管原型没有定义 console.log(({}) instanceof Object); // 返回 true, 同上 console.log(myNonObj instanceof Object); // 返回 false, 一种创建非 Object 实例的对象的方法 console.log(myString instanceof Date); //返回 false console.log( myDate instanceof Date); // 返回 true console.log(myDate instanceof Object); // 返回 true console.log(myDate instanceof String); // 返回 false
注意:instanceof运算符的左边必须是一个对象,像"string" instanceof String,true instanceof Boolean这样的字面量都会返回false。
下面代码创建了一个类型Car,以及该类型的对象实例mycar,instanceof运算符表明了这个myca对象既属于Car类型,又属于Object类型。
function Car(make, model, year) { this.make = make; this.model = model; this.year = year; } var mycar = new Car("Honda", "Accord", 1998); var a = mycar instanceof Car; // 返回 true var b = mycar instanceof Object; // 返回 true
不是...的实例
要检测对象不是某个构造函数的实例时,可以使用!运算符,例如if(!(mycar instanceof Car))
instanceof虽然能够判断出对象的类型,但是必须要求这个参数是一个对象,简单类型的变量,字面量就不行了,很显然,这在实际编码中也是不够实用。
总结:obj instanceof constructor虽然能判断出对象的原型链上是否有构造函数的原型,但是只能判断出对象类型变量,字面量是判断不出的。
3. Object.prototype.toString()
3.1. 语法
toString()方法返回一个表示该对象的字符串。
语法:obj.toString()
返回值:一个表示该对象的字符串
描述:每个对象都有一个toString()方法,该对象被表示为一个文本字符串时,或一个对象以预期的字符串方式引用时自动调用。默认情况下,toString()方法被每个Object对象继承,如果此方法在自定义对象中未被覆盖,toString()返回“[object type]”,其中type是对象的类型,看下面代码:
var o = new Object(); console.log(o.toString()); // returns [object Object]
注意:如ECMAScript 5和随后的Errata中所定义,从javascript1.8.5开始,toString()调用null返回[object, Null],undefined返回[object Undefined]
3.2. 示例
覆盖默认的toString()方法
可以自定义一个方法,来覆盖默认的toString()方法,该toString()方法不能传入参数,并且必须返回一个字符串,自定义的toString()方法可以是任何我们需要的值,但如果带有相关的信息,将变得非常有用。
下面代码中定义Dog对象类型,并在构造函数原型上覆盖toString()方法,返回一个有实际意义的字符串,描述当前dog的姓名,颜色,性别,饲养员等信息。
function Dog(name,breed,color,sex) { this.name = name; this.breed = breed; this.color = color; this.sex = sex; } Dog.prototype.toString = function dogToString() { return "Dog " + this.name + " is a " + this.sex + " " + this.color + " " + this.breed } var theDog = new Dog("Gabby", "Lab", "chocolate", "female"); console.log(theDog.toString()) //Dog Gabby is a female chocolate Lab
4. 使用toString()检测数据类型
目前来看toString()方法能够基本满足javascript数据类型的检测需求,可以通过toString()来检测每个对象的类型。为了每个对象都能通过Object.prototype.toString()来检测,需要以Function.prototype.call()或者Function.prototype.apply()的形式来检测,传入要检测的对象或变量作为第一个参数,返回一个字符串"[object type]"。
// null undefined console.log(Object.prototype.toString.call(null)) //[object Null] 很给力 console.log(Object.prototype.toString.call(undefined)) //[object Undefined] 很给力 // Number console.log(Object.prototype.toString.call(Infinity)) //[object Number] console.log(Object.prototype.toString.call(Number.MAX_SAFE_INTEGER)) //[object Number] console.log(Object.prototype.toString.call(NaN)) //[object Number],NaN一般是数字运算得到的结果,返回Number还算可以接受 console.log(Object.prototype.toString.call(1)) //[object Number] var n = 100 console.log(Object.prototype.toString.call(n)) //[object Number] console.log(Object.prototype.toString.call(0)) // [object Number] console.log(Object.prototype.toString.call(Number(1))) //[object Number] 很给力 console.log(Object.prototype.toString.call(new Number(1))) //[object Number] 很给力 console.log(Object.prototype.toString.call('1')) //[object String] console.log(Object.prototype.toString.call(new String('2'))) // [object String] // Boolean console.log(Object.prototype.toString.call(true)) // [object Boolean] console.log(Object.prototype.toString.call(new Boolean(1))) //[object Boolean] // Array console.log(Object.prototype.toString.call(new Array(1))) // [object Array] console.log(Object.prototype.toString.call([])) // [object Array] // Object console.log(Object.prototype.toString.call(new Object())) // [object Object] function foo() {} let a = new foo() console.log(Object.prototype.toString.call(a)) // [object Object] // Function console.log(Object.prototype.toString.call(Math.floor)) //[object Function] console.log(Object.prototype.toString.call(foo)) //[object Function] // Symbol console.log(Object.prototype.toString.call(Symbol('222'))) //[object Symbol] // RegExp console.log(Object.prototype.toString.call(/sss/)) //[object RegExp]
上面的结果,除了NaN返回Number稍微有点差池之外其他的都返回了意料之中的结果,都能满足实际开发的需求,于是我们可以写一个通用的函数来检测变量,字面量的类型。如下:
let Type = (function () { let type = {}; let typeArr = ['String', 'Object', 'Number', 'Array', 'Undefined', 'Function', 'Null', 'Symbol', 'Boolean', 'RegExp', 'BigInt']; for (let i = 0; i < typeArr.length; i++) { (function (name) { type['is' + name] = function (obj) { return Object.prototype.toString.call(obj) === '[object ' + name + ']' } })(typeArr[i]) } return type })() let s = true console.log(Type.isBoolean(s)) // true console.log(Type.isRegExp(/22/)) // true
除了能检测ECMAScript规定的八种数据类型(七种原始类型,Boolean,Null,Undefined,Number,BigInt,String,Symbol,一种复合类型Object)之外,还能检测出正则表达式RegExp,Function这两种类型,基本上能满足开发中的判断数据类型需求。
5. 判断相等
既然说道这里,不妨说一说另一个开发中常见的问题,判断一个变量是否等于一个值。ES5中比较两个值是否相等,可以使用相等运算符(==),严格相等运算符(===),但它们都有缺点,== 会将‘4’转换成4,后者NaN不等于自身,以及+0 !=== -0。ES6中提出”Same-value equality“(同值相等)算法,用来解决这个问题。Object.is就是部署这个算法的新方法,它用来比较两个值是否严格相等,与严格比较运算(===)行为基本一致。
console.log(5 == '5') // true console.log(NaN == NaN) // false console.log(+0 == -0) // true console.log({} == {}) // false console.log(5 === '5') // false console.log(NaN === NaN) // false console.log(+0 === -0) // true console.log({} === {}) // false
Object.js()不同之处有两处,一是+0不等于-0,而是NaN等于自身,如下:
let a = {} let b = {} let c = b console.log(a === b) // false console.log(b === c) // true console.log(Object.is(b, c)) // true
注意两个空对象不能判断相等,除非是将一个对象赋值给另外一个变量,对象类型的变量是一个指针,比较的也是这个指针,而不是对象内部属性,对象原型等。
本文来自 js教程 栏目,欢迎学习!
以上がJavaScript でデータ型を決定するいくつかの方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。