Appearance
数据类型检测
检测方法
typeof
typeof xxx
得到的值有以下几种类型:undefined
boolean
number
string
object
function
、symbol
,比较简单,不再一一演示了。这里需要注意的有三点:
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
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
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
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
2
3
值类型 vs 引用类型
除了原始类型,ES 还有引用类型,上文提到的typeof
识别出来的类型中,只有object
和function
是引用类型,其他都是值类型。
根据 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
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
2
3
4
5
6
7
上述代码中,a
b
都是引用类型。在执行了b = a
之后,修改b
的属性值,a
的也跟着变化。因为a
和b
都是引用类型,指向了同一个内存地址,即两者引用的是同一个值,因此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
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
2
3
4
5
6
7
8
9
10
虽然obj
本身是个引用类型的变量(对象),但是内部的a
和b
一个是值类型一个是引用类型,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
2
3
4
5
6
7
8
简单版
javascript
let hasPubProperty = function hasPubProperty(obj, attr) {
return attr in obj && obj.hasOwnProperty(attr);
};
1
2
3
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
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
2
3
4
5