浅析instanceof与constructor

先上一张原型链示意图及三段对理解instanceof与constructor机制有帮助的代码:

原型链图示

how-prototypes-work

对理解有帮助的代码段

下面的代码是new一个新对象的过程

/* new 一个新对象的内部机制 */

function A(){}
var a = {};
a = {__proto__:A.prototype};
A.call(obj);

下面的代码用来证明以上的结论

function A() {}
var a = new A();
alert(a.__proto__ === A.prototype); //true

下面代码证明变量名只是对对象的引用

var b = {
  value:1
}

var a = b;

var b = {
  value:2
}

alert(a.value) //1

下面分别用十二个实例来剖析instanceof与constructor的内部机制,请在Firefox下,且firebug控制台启用的时浏览此Demo instanceof – constructor.html

1 常规对象实例化

/* 常规对象实例化 */
function A() {
  this.attribute = 'a';
}

A.prototype.method = function(){
  console.info(this.attribute)
}

console.log('常规对象实例化'); 

var a = new A();

a.method();

console.info(a.constructor == A) //true
console.info(a instanceof A)     //true

2 根据推测出的对象实例化机制实例化对象

/* 根据推测出的对象实例化机制实例化对象 */
function A(){
  this.attribute = 'a';
}

A.prototype.method = function(){
  console.info(this.attribute)
}

console.log('根据推测出的对象实例化机制实例化对象'); 
  
var a = {};
a = {__proto__:A.prototype};
A.call(a);

a.method();

console.info(a.constructor == A) //true
console.info(a instanceof A)     //true

3 不建议的实例化一

下面的代码执行后会改变 b.constructor

/* 不建议的实例化一 */
function B(){
  this.attribute = 'b';
}

B.prototype = {
  method:function(){
    console.info(this.attribute)
  }
}

console.log('不建议的实例化一,这样的实例化会使b.constructor == B 输出false'); 

var b = {};
b = {__proto__:B.prototype};
B.call(b);

b.method();

console.info(b.constructor == B) //false
console.info(b instanceof B)     //true

4 修改不建议的实例化一

更改b.constructor的指针,重新使得 b.constructor = B

/* 修改不建议的实例化一 */
function B(){
  this.attribute = 'b';
}

B.prototype = {
  method:function(){
    console.info(this.attribute)
  },
  constructor:B  //将B.prototype.constructor指向B
}

console.log('修改不建议的实例化一,使得b.constructor == B 输出true'); 
  
var b = {};
b = {__proto__:B.prototype};
B.call(b);

b.method();

console.info(b.constructor == B) //true
console.info(b instanceof B)     //true

5 不建议的实例化二

下面的代码,实例化对象后执行对象构造函数的方法会导致错误

/* 不建议的实例化二 */
function C(){
  this.attribute = 'c';
  C.prototype = {
    method:function(){
      console.info(this.attribute)
    }
  }
}

console.log('不建议的实例化二,虽然此例子中表面上c.constructor == C,c instanceof C 都输出true,但实际上这样写浏览器会报错,为避免终止下面代码运行,我将实例化后的对象的方法注释掉'); 

var c = {};
c = {__proto__:C.prototype};
C.call(c);

//c.method();

console.info(c.constructor == C) //true,默认值每个构造
函数.prototype.constructor = 构造函数本身
console.info(c instanceof C)     //false

6 修改不建议的实例化二

JS是一种解释型语,当执行C.call(c)时,构造函数的内部代码才开始执行,

1 执行后,运行 c = {__proto__:C.prototype} 才变得有意义,这时c对象被改变了,所以要给c.attribute赋值;

2 执行后,使得C.prototype指向的是一个新对象,所以要绑定C.prototype.constructor = C 才能使得 c.constructor = C

/* 修改不建议的实例化二 */
function C(){
  this.attribute = 'c';
  C.prototype = {
    method:function(){
      console.info(this.attribute)
    },
    constructor:C
  }
}

console.log('修改的实例化二');

var c = {};
C.call(c);
c = {__proto__:C.prototype,attribute:c.attribute};

c.method();

console.info(c.constructor == C) //true
console.info(c instanceof C)     //true

7 一个值得思考的实例

/* 一个值得思考的实例 */
function D(){
  this.attribute = 'd';
}

D.prototype.method = function() {
  console.info(this.attribute);
}

console.log('一个值得思考的实例')
;
var d = {};
d = {__proto__:D.prototype};
D.call(d);

D.prototype = {};  //更改构造函数prototype

d.method();

console.info(d.constructor == D) //true
console.info(d instanceof D)     //false

8 常规实例化继承

/* 常规实例化继承 *
function E() {
  this.attribute = 'e';
}

E.prototype.method = function(){
  console.info(this.attribute);
}

function F() {}
F.prototype = new E();

console.log('常规实例化继承,两个函数E()、F(),F继承E,f为F()的实例,发现异常f.constructor == F 输出为false'); 

f = new F();

f.method();

console.info(f.constructor == E) //true
console.info(f instanceof E)     //true
console.info(f.constructor == F) //false
console.info(f instanceof F)     //true

9 根据推测出的对象实例化机制继承

/* 根据推测出的对象实例化机制继承 */
function E() {
  this.attribute = 'e';
}

E.prototype.method = function(){
  console.info(this.attribute)
}

function F() {}

F.prototype = {};
F.prototype = {__proto__:E.prototype};
E.call(F.prototype); //或者在实例化后加上E.call(f);

console.log('根据推测出的对象实例化机制继承,两个函数E()、F(),F继承E,f为
F()的实例,发现异常f.constructor == F 输出为false'); 

f = {};
f = {__proto__:F.prototype};

f.method();

console.info(f.constructor == E) //true
console.info(f instanceof E)     //true
console.info(f.constructor == F) //false
console.info(f instanceof F)     //true

10 根据推测出的对象实例化机制继承,更改constructor指针

/* 根据推测出的对象实例化机制继承,更改constructor指针 */
function E() {
  this.attribute = 'e';
}

E.prototype.method = function(){
  console.info(this.attribute)
}

function F() {}

F.prototype = {};
F.prototype = {__proto__:E.prototype,constructor:F = E};
E.call(F.prototype); //或者在实例化后加上E.call(f);

console.log('根据推测出的对象实例化机制继承,两个函数E()、F(),F继承E,f为F()的实例,排除上例中异常 f.constructor == F 输出为true'); 

f = {};
f = {__proto__:F.prototype};

f.method();

console.info(f.constructor == E) //true
console.info(f instanceof E)     //true
console.info(f.constructor == F) //true
console.info(f instanceof F)     //true

11 prototype遍历继承

/* prototype遍历继承 */
function G() {
  this.attribute = 'g';
}

G.prototype.method = function(){
  console.info(this.attribute)
}

function H() {}
  for(var x in G.prototype) {
  H.prototype[x] = G.prototype[x];
}

G.call(H.prototype);

console.log('prototype遍历继承,两个函数G()、H(),H继承G,h为H()的实例,发现 h.constructor == G,h instanceof G 均输出为false'); 

h = new H();

h.method();

console.info(h.constructor == G) //false
console.info(h instanceof G)     //false
console.info(h.constructor == H) //true
console.info(h instanceof H)     //true

12 prototype遍历继承,增添instanceof constructor

/* prototype遍历继承,增添instanceof constructor */
function G() {
  this.attribute = 'g';
}

G.prototype.method = function(){
  console.info(this.attribute)
}

function H() {}
  for(var x in G.prototype) {
  H.prototype[x] = G.prototype[x];
}

H.prototype.__proto__ = G.prototype;  //增添instanceof
H.prototype.constructor = H = G;      //增添constructor
G.call(H.prototype);

console.log('prototype遍历继承,两个函数G()、H(),H继承G,h为H()的实例,h.constructor == G,h instanceof G 均输出为true');

h = new H();

h.method();

console.info(h.constructor == G) //true
console.info(h instanceof G)     //true
console.info(h.constructor == H) //true
console.info(h instanceof H)     //true

需要注意的问题

1 逻辑问题

由于以上十二段代码都写在同一个页面中,虽然已测试输出在console中的结果,但细究代码逻辑上是有问题的,比如:

您会发现页面中不同的例子有着相同名字的函数,原意是想让各自执行例子中包含的函数,但实际由于同名函数在一个页面中,预解析时后出现的函数一定会覆盖已经定义的同名函数,所以无论在页面中什么位置执行同名函数都是在执行同一函数。

您若对instanceof与constructor感兴趣,建议分开测试每一段代码。

2 排版问题

出于页面正文宽度限制,将较为长的单行代码分为多行展示,若拷贝以上代码,需将其改为单行,否则浏览器会报错。

This entry was posted in Javascript/Ajax and tagged , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

2 Comments

  1. superzengjiangli
    Posted 2010年09月8日 at 9:10 上午 | Permalink

    楼主的例子很经典,我费了大半天的时间才全部弄懂~~
    如果能加上一些解释就更好了~

  2. 一滴雨
    Posted 2010年09月8日 at 10:11 上午 | Permalink

    确实需要说的更明白些,谢谢您!

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Free Web Hosting