所在的位置: js >> js发展 >> js中的内省

js中的内省

北京哪治疗白癜风医院收费低 http://pf.39.net/bdfyy/bdfzg/150215/4579770.html

内省

如果你写过许多面向类的程序(无论是使用JavaScript还是其他语言),那你可能很熟悉自省。自省就是检查实例的类型。类实例的自省主要目的是通过创建方式来判断对象的结构和功能。

下面的代码使用instanceof来推测对象a1的功能:

因为Foo.prototype(不是Foo!)在a1的[[Prototype]]链上,所以instanceof操作(会令人困惑地)告诉我们a1是Foo“类”的一个实例。知道了这点后,我们就可以认为a1有Foo“类”描述的功能。

当然,Foo类并不存在,只有一个普通的函数Foo,它引用了a1委托的对象(Foo.prototype)。从语法角度来说,instanceof似乎是检查a1和Foo的关系,但是实际上它想说的是a1和Foo.prototype(引用的对象)是互相关联的。

instanceof语法会产生语义困惑而且非常不直观。如果你想检查对象a1和某个对象的关系,那必须使用另一个引用该对象的函数才行——你不能直接判断两个对象是否关联。

简单来说是这样的:

如果要使用instanceof和.prototype语义来检查本例中实体的关系,那必须这样做:

显然这是一种非常糟糕的方法。举例来说,(使用类时)你最直观的想法可能是使用BarinstanceofFoo(因为很容易把“实例”理解成“继承”),但是在JavaScript中这是行不通的,你必须使用Bar.prototypeinstanceofFoo。

还有一种常见但是可能更加脆弱的内省模式,许多开发者认为它比instanceof更好。这种模式被称为“鸭子类型”。这个术语源自这句格言“如果看起来像鸭子,叫起来像鸭子,那就一定是鸭子。”

举例来说:

if(a1.something){

a1.something();

}

我们并没有检查a1和委托something()函数的对象之间的关系,而是假设如果a1通过了测试a1.something的话,那a1就一定能调用.something()(无论这个方法存在于a1自身还是委托到其他对象)。这个假设的风险其实并不算很高。

但是“鸭子类型”通常会在测试之外做出许多关于对象功能的假设,这当然会带来许多风险(或者说脆弱的设计)。

ES6的Promise就是典型的“鸭子类型”

出于各种各样的原因,我们需要判断一个对象引用是否是Promise,但是判断的方法是检查对象是否有then()方法。换句话说,如果对象有then()方法,ES6的Promise就会认为这个对象是“可持续”(thenable)的,因此会期望它具有Promise的所有标准行为。

如果有一个不是Promise但是具有then()方法的对象,那你千万不要把它用在ES6的Promise机制中,否则会出错。

这个例子清楚地解释了“鸭子类型”的危害。你应该尽量避免使用这个方法,即使使用也要保证条件是可控的。

对象关联风格代码,其内省更加简洁。我们先来回顾一下之前的Foo/Bar/b1对象关联例子(只包含关键代码):

使用对象关联时,所有的对象都是通过[[Prototype]]委托互相关联,下面是内省的方法,非常简单:

我们没有使用instanceof,因为它会产生一些和类有关的误解。现在我们想问的问题是“你是我的原型吗?”我们并不需要使用间接的形式,比如Foo.prototype或者繁琐的Foo.prototype.isPrototypeOf(..)。

我觉得和之前的方法比起来,这种方法显然更加简洁并且清晰。再说一次,我们认为JavaScript中对象关联比类风格的代码更加简洁(而且功能相同)。




转载请注明:http://www.aierlanlan.com/tzrz/1721.html