Skip to content
On this page

数据类型检测

检测方法

typeof

typeof xxx得到的值有以下几种类型:undefined boolean number string object functionsymbol ,比较简单,不再一一演示了。这里需要注意的有三点:

  • typeof null结果是object ,实际这是typeof的一个 bug,null 是原始值,非引用类型
  • typeof [1, 2]结果是object,结果中没有array这一项,引用类型除了function其他的全部都是object
  • typeof Symbol()typeof获取symbol类型的值得到的是symbol,这是 ES6 新增的知识点

instanceof

用于实例和构造函数的对应。例如判断一个变量是否是数组,使用typeof无法判断,但可以使用[1, 2] instanceof Array来判断。因为,[1, 2]是数组,它的构造函数就是Array。同理:

javascript
function Fn() {
  var n = 10;
  this.m = n;
}
var f = new Fn();
1
2
3
4
5

检测某一个实例是否隶属于这个类

javascript
console.log(f instanceof Fn); // => TRUE
console.log(f instanceof Array); // => FALSE
console.log(f instanceof Object); // => TRUE (万物皆对象:所有的对象,包含创建的实例都是 Object 的实例)
1
2
3

in

检测当前对象是否存在某个属性(不管当前这个属性是对象的私有属性还是公有属性,只要有结果就是 TRUE)

javascript
console.log("m" in f); //=>TRUE
console.log("n" in f); //=>FALSE
console.log("toString" in f); //=>TRUE toString 是它的公有属性
1
2
3

hasOwnProperty

检测当前属性是否为对象的私有属性(不仅要有这个属性,而且必须还是私有的才可以)

javascript
console.log(f.hasOwnProperty("m")); //=>TRUE
console.log(f.hasOwnProperty("n")); //=>FALSE 连这个属性都没有
console.log(f.hasOwnProperty("toString")); //=>FALSE 虽然有这个属性但是不是私有的属性
1
2
3

值类型 vs 引用类型

除了原始类型,ES 还有引用类型,上文提到的typeof识别出来的类型中,只有objectfunction是引用类型,其他都是值类型。

根据 JavaScript 中的变量类型传递方式,又分为值类型引用类型,值类型变量包括 Boolean、String、Number、Undefined、Null,引用类型包括了 Object 类的所有,如 Date、Array、Function 等。在参数传递方式上,值类型是按值传递,引用类型是按共享传递。

下面通过一个小题目,来看下两者的主要区别,以及实际开发中需要注意的地方。

javascript
// 值类型
var a = 10
var b = a
b = 20
console.log(a)  // 10
console.log(b)  // 20

1
2
3
4
5
6
7

上述代码中,a b都是值类型,两者分别修改赋值,相互之间没有任何影响。再看引用类型的例子:

js
// 引用类型
var a = {x: 10, y: 20}
var b = a
b.x = 100
b.y = 200
console.log(a)  // {x: 100, y: 200}
console.log(b)  // {x: 100, y: 200}
1
2
3
4
5
6
7

上述代码中,a b都是引用类型。在执行了b = a之后,修改b的属性值,a的也跟着变化。因为ab都是引用类型,指向了同一个内存地址,即两者引用的是同一个值,因此b修改属性时,a的值随之改动。

再借助题目进一步讲解一下。

说出下面代码的执行结果,并分析其原因。

js
function foo(a){
    a = a * 10;
}
function bar(b){
    b.value = 'new';
}
var a = 1;
var b = {value: 'old'};
foo(a);
bar(b);
console.log(a); // 1
console.log(b); // value: new
1
2
3
4
5
6
7
8
9
10
11
12

通过代码执行,会发现:

  • a的值没有发生改变
  • b的值发生了改变

这就是因为Number类型的a是按值传递的,而Object类型的b是按共享传递的。

JS 中这种设计的原因是:按值传递的类型,复制一份存入栈内存,这类类型一般不占用太多内存,而且按值传递保证了其访问速度。按共享传递的类型,是复制其引用,而不是整个复制其值(C 语言中的指针),保证过大的对象等不会因为不停复制内容而造成内存的浪费。

引用类型经常会在代码中按照下面的写法使用,或者说容易不知不觉中造成错误

js
var obj = {
    a: 1,
    b: [1,2,3]
}
var a = obj.a
var b = obj.b
a = 2
b.push(4)
console.log(obj, a, b)

1
2
3
4
5
6
7
8
9
10

虽然obj本身是个引用类型的变量(对象),但是内部的ab一个是值类型一个是引用类型,a的赋值不会改变obj.a,但是b的操作却会反映到obj对象上。

编写一个方法 hasPubProperty

检测当前属性是否为对象的公有属性,和 hasOwnProperty 对应

javascript
function hasPubProperty(obj, attr) {
  //=>OBJ:要检测的对象
  //=>ATTR:要检测的属性
  //...
}
hasPubProperty(f, "m"); //=>FALSE
hasPubProperty(f, "n"); //=>FALSE
hasPubProperty(f, "toString"); //=>TRUE
1
2
3
4
5
6
7
8

简单版

javascript
let hasPubProperty = function hasPubProperty(obj, attr) {
  return attr in obj && obj.hasOwnProperty(attr);
};
1
2
3

完美版

javascript
Object.prototype.hasPubProperty = function hasPubProperty(attr) {
  let self = this;
  let protoType = Object.getPrototypeOf(self);
  while (protoType) {
    if (protoType.hasOwnProperty(attr)) return true;
    protoType = Object.getPrototypeOf(protoType);
  }
  return false;
};
1
2
3
4
5
6
7
8
9

完美简化版

javascript
Object.prototype.hasPubProperty = function hasPubProperty(attr) {
  let protoType = Object.getPrototypeOf(self);
  //in操作符检测的特点:先看自己私有中是否有,如果没有会默认按原型链一层层查找
  return attr in protoType;
};
1
2
3
4
5
沪ICP备20006251号-1