1.typeof
下表总结了 typeof 可能的返回值。有关类型和基本类型的更多信息,可查看 JavaScript 数据结构 页面。
| 类型 | 结果 |
|---|---|
| Undefined | "undefined" |
| Null | "object"(原因) |
| Boolean | "boolean" |
| Number | "number" |
| BigInt | "bigint" |
| String | "string" |
| Symbol | "symbol" |
| Function(在 ECMA-262 中实现 [[Call]];classes也是函数) | "function" |
| 其他任何对象(数组、对象、null) | "object" |
// 数值
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof(42) === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管它是 "Not-A-Number" (非数值) 的缩写
typeof Number(1) === 'number'; // Number 会尝试把参数解析成数值
typeof Number("shoe") === 'number'; // 包括不能将类型强制转换为数字的值
typeof 42n === 'bigint';
// 字符串
typeof '' === 'string';
typeof 'bla' === 'string';
typeof `template literal` === 'string';
typeof '1' === 'string'; // 注意内容为数字的字符串仍是字符串
typeof (typeof 1) === 'string'; // typeof 总是返回一个字符串
typeof String(1) === 'string'; // String 将任意值转换为字符串,比 toString 更安全
// 布尔值
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(1) === 'boolean'; // Boolean() 会基于参数是真值还是虚值进行转换
typeof !!(1) === 'boolean'; // 两次调用 !(逻辑非)运算符相当于 Boolean()
// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';
// Undefined
typeof undefined === 'undefined';
typeof declaredButUndefinedVariable === 'undefined';
typeof undeclaredVariable === 'undefined';
// 对象
typeof { a: 1 } === 'object';
// 使用 Array.isArray 或者 Object.prototype.toString.call
// 区分数组和普通对象
typeof [1, 2, 4] === 'object';
typeof new Date() === 'object';
typeof /regex/ === 'object';
// 下面的例子令人迷惑,非常危险,没有用处。避免使用它们。
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';
// 函数
typeof function() {} === 'function';
typeof class C {} === 'function'
typeof Math.sin === 'function';
// JavaScript 诞生以来便如此
typeof null === "object";
2.instanceof (object instanceof constructor)
object:某个实例对象,constructor:某个构造函数;
instanceof 运算符用来检测(构造函数的 prototype 属性) constructor.prototype 是否存在于参数 (实例对象)object` 的原型链上。
//eg:
// 定义构造函数
function C(){}
function D(){}
var o = new C();
o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false,因为 D.prototype 不在 o 的原型链上
o instanceof Object; // true,因为 Object.prototype.isPrototypeOf(o) 返回 true
C.prototype instanceof Object // true,同上
//eg:
C.prototype = {};
var o2 = new C();
o2 instanceof C; // true
o instanceof C; // false,C.prototype 指向了一个空对象,这个空对象不在 o 的原型链上。
//eg:
D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true 因为 C.prototype 现在在 o3 的原型链上
要检测对象不是某个构造函数的实例时,你可以这样做
if (!(mycar instanceof Car)) {}
`String` 和 `Date` 对象同时也属于`Object` 类型(他们是由 `Object` 类派生出来的)
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);
simpleStr instanceof String; // 返回 false,非对象实例,因此返回 false
myString instanceof String; // 返回 true
newStr instanceof String; // 返回 true
myString instanceof Object; // 返回 true
myObj instanceof Object; // 返回 true,尽管原型没有定义
({}) instanceof Object; // 返回 true,同上
myNonObj instanceof Object; // 返回 false,一种创建非 Object 实例的对象的方法
myString instanceof Date; //返回 false
myDate instanceof Date; // 返回 true
myDate instanceof Object; // 返回 true
myDate instanceof String; // 返回 false
类型 `Car`,以及该类型的对象实例 `mycar`. `instanceof` 运算符表明了这个 `mycar` 对象既属于 `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
3.constructor
Object.prototype.constructor,constructor 属性返回 Object 的构造函数(用于创建实例对象)。注意,此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。
原始类型的值是只读的,如:1、true 和 "test"。
所有对象(使用 Object.create(null) 创建的对象除外)都将具有 constructor 属性。在没有显式使用构造函数的情况下,创建的对象(例如对象和数组文本)将具有 constructor 属性,这个属性指向该对象的基本对象构造函数类型。
const o = {}
o.constructor === Object // true
const o = new Object
o.constructor === Object // true
const a = []
a.constructor === Array // true
const a = new Array
a.constructor === Array // true
const n = new Number(3)
n.constructor === Number // true
function Tree(name) {
this.name = name
}
const theTree = new Tree('Redwood')
console.log( theTree.constructor) // function Tree(name) {this.name = name}
可以为除了 `null` 和 `undefined`(因为这两者没有相应的构造函数)之外的任何类型指定 `constructor` 属性(如 `String`、`Number`、`Boolean` 等),但基本类型不会保留这些更改(也不会抛出异常)。也是同样的原因,基本类型允许设置任何属性(除了 `null` 和 `undefined`),而不会产生副作用。就是说,每当把这样的基本类型当成对象使用时,其对应的构造函数的实例就会在语句执行后立即被创建和丢弃。
let val = null;
val.constructor = 1; // TypeError: val is null
val = 'abc';
val.constructor = Number; // val.constructor === String
val.foo = 'bar'; // An implicit instance of String('abc') was created and assigned the prop foo
val.foo === undefined; // true, since a new instance of String('abc') was created for this comparison, which doesn't have the foo property
因此,基本上除了上面的提到的基本类型外,任何对象都可以更改 `constructor` 属性的值,**请注意,改变** `constructor` **的属性不会影响** `instanceof` **运算符**:
let a = [];
a.constructor = String
a.constructor === String // true
a instanceof String // false
a instanceof Array // true
a = new Foo();
a.constructor = 'bar'
a.constructor === 'bar' // true
如果对象被密封或冻结,那么更改 constructor 将不会起作用,也不会抛出异常:
let a = Object.seal({});
a.constructor = Number;
a.constructor === Object; // true
大多数情况下,此属性用于定义一个**函数的构造函数(function-constructor)** ,并使用 **new** 和原型链继承进一步使用它。
function Parent() { /* ... */ }
Parent.prototype.parentMethod = function parentMethod() {}
function Child() {
Parent.call(this) // Make sure everything is initialized properly
}
Child.prototype = Object.create(Parent.prototype) // re-define child prototype to Parent prototype
Child.prototype.constructor = Child // return original constructor to Child