JavaScript中typeof、toString、instanceof、constructor与in

简介: JavaScript 是一种弱类型或者说动态语言。这意味着你不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。

JavaScript 是一种弱类型或者说动态语言。这意味着你不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。

这也意味着你可以使用同一个变量保存不同类型的数据。

最新的 ECMAScript 标准定义了 7 种数据类型

7种内置类型:Boolean、Null、Undefined、Number、String、Symbol (ECMAScript 6 新定义)和Object,除 Object 以外的所有类型都是不可变的(值本身无法被改变)。

 

一、typeof


typeof操作符返回一个字符串,表示未经求值的操作数(unevaluated operand)的类型。查看在线代码


// Numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管NaN是"Not-A-Number"的缩写,意思是"不是一个数字"
typeof Number(1) === 'number'; // 不要这样使用!
// Strings
typeof "" === 'string';
typeof "bla" === 'string';
typeof (typeof 1) === 'string'; // typeof返回的肯定是一个字符串
typeof String("abc") === 'string'; // 不要这样使用!
// Booleans
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(true) === 'boolean'; // 不要这样使用!
// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';
// Undefined
typeof undefined === 'undefined';
typeof blabla === 'undefined'; // 一个未定义的变量,或者一个定义了却未赋初值的变量
// Objects
typeof {a:1} === 'object';
// 使用Array.isArray或者Object.prototype.toString.call方法可以从基本的对象中区分出数组类型
typeof [1, 2, 4] === 'object';
typeof new Date() === 'object';
// 下面的容易令人迷惑,不要这样使用!
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String("abc") === 'object';
// 从JavaScript一开始出现就是这样的 
typeof null === 'object';// 正则表达式
typeof /s/ === 'object'; // Chrome 12+ , 符合 ECMAScript 5.1
typeof /s/ === 'object'; // Firefox 5+ , 符合 ECMAScript 5.1
// 函数
typeof function(){} === 'function';
typeof Math.sin === 'function';
typeof /s/ === 'function'; // Chrome 1-12 , 不符合 ECMAScript 5.1

undefined(未赋值)和undeclared(未声明)是有区别的。

检查全局变量的是否声明的安全防范机制:


typeof DEBUG == "undefined"
//或
window.DEBUG


二、toString


可以通过使用toString.call(obj)来检测对象类型。

可以用来检测ObjectNumberArrayDateFunctionStringBooleanErrorRegExp

下面的代码与上面的代码做了一一比较,其中在注释中有标红的“不同”,说明有区别。查看在线代码


var toString = Object.prototype.toString;
// Numbers 都返回[object Number]
toString.call(37);
toString.call(3.14);
toString.call(Math.LN2);
toString.call(Infinity);
toString.call(Number(1));
// Strings 都返回[object String]
toString.call("");
toString.call("bla");
toString.call(String("abc"));
// Booleans 都返回[object Boolean]
toString.call(true);
toString.call(false);
toString.call(Boolean(true));
// Symbols 都返回[object Symbol]
toString.call(Symbol());
toString.call(Symbol('foo'));
toString.call(Symbol.iterator);
// Undefined 都返回[object Undefined]
toString.call(undefined);
//toString.call(blabla);//不同 一个未定义的变量会报错
// Objects
toString.call({a:1});//[object Object]
toString.call([1, 2, 4]);//[object Array] 不同
toString.call(new Date());//[object Date] 不同
toString.call(new Boolean(true));//[object Boolean] 不同
toString.call(new Number(1));//[object Number] 不同
toString.call(new String("abc"));//[object String] 不同
toString.call(null);//[object Null] 不同
toString.call(/s/);//[object RegExp] 不同
toString.call(new TypeError());//[object Error] 不同
// 函数 都返回[object Function]
toString.call(function(){});
toString.call(Math.sin);


三、instanceof


instanceof 运算符可以用来判断某个构造函数的 prototype 属性是否存在另外一个要检测对象的原型链上,返回boolean值。语法如下:


image.png


也就比对object.__proto__与constructor.prototype是否对应。

JavaScript instanceof 运算符代码,参考自《JavaScript instanceof 运算符深入剖析


function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
  var O = R.prototype;// 取 R 的显示原型
  L = L.__proto__;// 取 L 的隐式原型
  while (true) { 
    if (L === null) 
      return false; 
    if (O === L)// 这里重点:当 O 严格等于 L 时,返回 true 
      return true; 
    L = L.__proto__; 
  } 
 }

object:要检测的对象,constructor:某个构造函数。查看在线代码


// 定义构造函数
function C(){}
function D(){}
var o = new C();
o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype
//o.__proto__={}; //改变o原型链,o instanceof C将会返回false
o instanceof D; // false,因为 D.prototype不在o的原型链上
o instanceof Object; // true,因为Object.prototype.isPrototypeOf(o)返回true
C.prototype instanceof Object // true,同上
C.prototype = {};
var o2 = new C();
o2 instanceof C; // true
o instanceof C; // false,C.prototype指向了一个空对象,这个空对象不在o的原型链上.
D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true


有两种方式可以将"o instanceof C"返回“false”:

1、注意上面代码的第12行,改变了函数C.prototype属性,改变之后导致这个对象不在o的原型链上。

2、改变对象o的原型链,借助于非标准的__proto__魔法属性可以实现。比如代码的第7行执行o.__proto__ = {}。

 

这里需要注意一个地方,就是Object.prototype.isPrototypeOf()与instanceof的区别。请看下面的代码


var human = function() {}
var socrates = Object.create(human);
console.log(human.isPrototypeOf(socrates)); // true
console.log(socrates instanceof human); // false
console.log(socrates.__proto__ == human.prototype);//false
console.log(socrates.__proto__ == human);//true


上面的Object.create()传递的是human函数,“socrates.__proto__ == human.prototype”不相等,

也就是说human.prototype不在socrates的原型链上,所以instanceof返回的是false。

isPrototypeOf() 是指测试一个对象是否存在于另一个对象的原型链上;现在human这个对象在socrates的原型链上。

 

四、constructor


constructor返回一个指向创建了该对象原型的函数引用。

需要注意的是,该属性的值是那个函数本身,而不是一个包含函数名称的字符串。对于原始值(如1,true 或 "test"),该属性为只读。

所有对象都会从它的原型上继承一个 constructor 属性。查看在线代码

1、在JavaScript的继承中,instanceof和constructor表现的是不一样的:


function C(){} 
function D(){} 
D.prototype = new C(); // 继承
var o = new D();
o instanceof D; // true
o instanceof C; // true
o.constructor == D; // false
o.constructor == C; // true
o.constructor == D.prototype.constructor;//true
o.constructor == Object.prototype.constructor;// false


对象的constructor属性是根据函数的prototype.constructor来的。

 

2、改变这个对象的constructor属性的值,只有 true, 1"test" 的不受影响,其他的都变成了"function type(){}"

function Type() { };
var    types = [
    new Array,
    [],
    new Boolean,
    true,        // remains unchanged
    new Date,
    new Error,
    new Function,
    function(){},
    Math,    
    new Number,
    1,           // remains unchanged
    new Object,
    {},
    new RegExp,
    /(?:)/,
    new String,
    "test"       // remains unchanged
];
for(var i = 0; i < types.length; i++) {
    types[i].constructor = Type;
    types[i] = [ types[i].constructor, types[i] instanceof Type, types[i].toString() ];
    console.log(types[i]);
};


下图分别是“new Boolean” 和 “true”的打印结果:

image.png

 


五、in


in操作,如果指定的属性在指定的对象中会返回true,语法如下:


image.png


1)与hasOwnProperty比较


hasOwnProperty() 方法用来判断某个对象是否含有指定的自身属性。

多了个自身。我的理解就是原型链上的公共属性,判断的时候会返回false。下面所有的代码都可以在线查看到


function colour() {
  this.a = 1;
}
colour.prototype.b = function() {
  return 2;
}
var mine = new colour();
console.log("a" in mine);//true
console.log("b" in mine);//true
console.log(mine.hasOwnProperty("a"));//true
console.log(mine.hasOwnProperty("b"));//false

2)用in判断对象属性


in判断的是数组或对象的key属性。数组是一类特殊的对象,数组具有length属性,而对象没有。可参考《对象和数组 (JavaScript)


var arr = ["a","b","c"];
console.log(0 in arr);//true
console.log(3 in arr);//false
var ob = {0:"a", 1:"b", 2:"c"};
console.log(0 in ob);//true
console.log(3 in ob);//false


上面的代码中数组的key是“0,1,2”与对象的key是一样的。

 

3)(delete)删除对象的属性


在使用delete后,属性判断都变成了“false”。


var arr = ["a","b","c"];
delete arr[0];
console.log(0 in arr);//false
var ob = {0:"a", 1:"b", 2:"c"};
delete ob[0];
console.log(0 in ob);//false

4)for...in循环


这里用上面示例中的对象mine。


for(property in mine) {
  console.log(property);
}


image.png

将会把上面的一个私有和公有的属性打印出来。这里注意,如果我在对象的公共父级(例如Object)中加个属性,也是会打印出来的。


Object.prototype.z = function() {
};


image.png

 


5)巧用in操作


if (value == "a" || value == "b" || value == "c") {
     //....
}
//替换为
if (value in {"a":"", "b":"", "c":""}) {
    //....
}



相关文章
|
3月前
|
JavaScript 前端开发
JavaScript基础知识-toString()
关于JavaScript基础知识中toString()方法的介绍。
29 1
JavaScript基础知识-toString()
|
3月前
|
JavaScript 前端开发
JS中toString和valueOf在什么时候会自动触发
本文探讨了JavaScript中`toString`和`valueOf`方法在何时会自动触发,解释了隐式类型转换时这两个方法的调用机制,并提供了多个代码示例来演示它们的自动触发情况。
34 1
|
3月前
|
机器学习/深度学习 JavaScript 前端开发
JavaScript typeof, null, 和 undefined
JavaScript typeof, null, 和 undefined
59 4
|
4月前
|
JavaScript 前端开发
JavaScript 中的 typeof 运算符
【8月更文挑战第29天】
27 1
|
4月前
|
JavaScript 前端开发
js确定数据类型typeof与instanceof
js确定数据类型typeof与instanceof
32 0
|
5月前
|
JavaScript
js【详解】instance of
js【详解】instance of
51 0
|
5月前
|
JavaScript
js【详解】typeof 运算符
js【详解】typeof 运算符
24 0
|
7月前
|
JavaScript 前端开发
前端 JS 经典:JS 基础类型和 typeof
前端 JS 经典:JS 基础类型和 typeof
37 0
|
7月前
|
前端开发 JavaScript
前端 JS 经典:typeof 和 instanceof 区别
前端 JS 经典:typeof 和 instanceof 区别
126 0
|
1月前
|
JavaScript 前端开发
JavaScript中的原型 保姆级文章一文搞懂
本文详细解析了JavaScript中的原型概念,从构造函数、原型对象、`__proto__`属性、`constructor`属性到原型链,层层递进地解释了JavaScript如何通过原型实现继承机制。适合初学者深入理解JS面向对象编程的核心原理。
25 1
JavaScript中的原型 保姆级文章一文搞懂