`
jj7jj7jj
  • 浏览: 50048 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

constructor与prototype的深入分析

阅读更多
平时只进不出,感觉也不怎么厚道,第一篇技术博客奉献给大家,希望大家有所收获

声明一下
constructor 指向的肯定是函数
prototype 指向的肯定是对象,并且只有function对象才具有此属性

希望看本文之前能先了解一下原型链概念

下面是对两个属性深层次的分析,欢迎拍砖

function fun(name){ 
	this.name = name;	
}

function fun2(name,age){
	fun.call(this,name);
	this.age = age;
}
var f1 = new fun();
var f2 = new fun2();

alert(f1.constructor); //fun(name){...}
alert(f2.constructor); //fun2(name,age){...}

    因为现在fun,fun2的prototype 默认都是Object,constructor由系统维护都是指向自己的,但是如果稍微改一下,情况就会发生变化了

fun2.prototype = new fun();
var f1 = ...

alert(f1.constructor); //fun(name){...}
alert(f2.constructor); //fun(name){...}

    这是为什么呢,因为用fun对象取代了默认fun2的原形,而fun又是自定义的,所以系统不会帮你维护constructor将其指向fun2,那么f2的constructor需要怎么处理,才能得到先前的效果

alert(f1.constructor == f2.constructor); //true

f1.constructor
fun.prototype.constructor
f2.constructor
fun2.prototype.constructor
f1.__proto__.constructor
f2.__proto__.constructor
实际上,上面这些都是相等

下面就开始讲原理了:

我们经常使用的new运算符,相当于干了以下工作:
var f1 = {};
f1.__proto__ = fun.prototype;
fun.call(f1);

    在执行f1.__proto__ = fun.prototype这一步的时候,系统会将f1.__proto__指向fun的原型(Object对象),而让fun的原型对象(Object对象)的constructor指向fun,所以当我打印的时候f1.constructor实际上就是打印fun原型的constructor,所以结果就是fun.

但是当我们执行fun2.prototype = new fun()的时候,相当于:
f2.__proto__ = new fun()

    这个时候f2.__proto__指向new fun() ( 假设new fun()对象叫funObj ),对原本f2.__proto__进行了重写 ,所以f2.constructor实际上就是funObj.constructor,而funObj.constructor实际上就是funObj.__proto__的constructor(原型链机制:在本对象中找不到的属性,会依次在原型链中找,直到找到为止),所以它再不会像上面一样帮你维护constructor的关系,所以当我们打印f2.constructor,显示的还是fun而不是fun2


但这样解释和标准有冲突
ECMASCRIPT标准里面定义了Object对象里面存在constructor,而且对象如果存在该属性的时候,就不会去原型链里面再去搜寻属性了,那么既然我们f2.constructor打印的是fun,也就证明本对象里面没有constructor属性(这样才会通过原型链去搜索)要么就是本对象的constructor属性被重写了,下面来做个实验

var aaa = {}; 
alert(aaa.constructor); //function Object(){ [native]}
alert(aaa.hasOwnProperty("constructor")) //false
alert(aaa.__proto__); //[object Object]
alert(aaa.__proto__.__proto__); //null

两点必须注意:
1.hasOwnProperty : 判断对象中是否有该属性,不会去检查原型链中的属性
2.除了function对象,其他的对象类型没有prototype属性

这就说明了对象字面量虽然没有像function对象的prototype,但__proto__属性从对象创建时就一直存在的,而且对象中的constructor实际不是对象本身的属性,而是aaa.__proto__(可以理解为原型,而且实际上它就是原型的本质)引用所指向的对象的属性,而且aaa.__proto__ 是aaa对象的顶级对象(或者说是aaa的根或者说aaa从它继承而来的),因为aaa.__proto__.__proto__为null


如果我将fun的原型设为null试试

function fun(name){ 
	this.name = name;	
}
fun.prototype = null;
...
var f1 = new fun();
alert(f1.constructor); //fuction Object(){ [native]}
alert(f1.__proto__); //[object Object]

虽然将fun的原型至为空,但f1.__proto__还是存在,证明fun.prototype置为null的时候对__proto__没影响就像默认的效果一样,如果不为空就会像f2.__proto__ = new fun()进行赋值。所以constructor的值永远存在的,当原型设为null或者不设的情况下就是默认的指向顶级元素,如果设置了就是原型的constructor属性

原理讲完了,那么怎么让f2.constructor指向fun2呢
两种方法
1. 一根筋型: f2.constructor = fun2 好处:只会对本对象产生效果
2. 策略型 : fun2.prototype.constructor = fun2 好处 : 对fun2的所有对象产生效果
(注意用for..in遍历的时候constructor属性会遍历出来)

function fun(name){ 
	this.name = name;	
}

function fun2(name,age){
	fun.call(this,name);
	this.age = age;
}

fun2.prototype = new fun();
fun2.prototype.constructor = fun2;

var f1 = new fun();
var f2 = new fun2();

alert(f1.constructor); //fun
alert(f2.constructor); //fun2
alert(f1.prototype); //undefined
alert(f2.prototype); //undefined

为什么prototype属性为undefined,因为只有function对象才有prototype属性,而f1,f2是obj对象(参考new运算符工作方式,上面提到过),那么怎么才能访问对象的原型类型
1. 直接型 f1.__proto__.constructor //[object Object]
2. 磨叽型 f2.constructor.prototype.constructor //fun
推荐第二种,毕竟__proto__这属性就压根不在标准中,只是为了理解原理所用


到此两个属性分析讲完了,不过我还是总结一下:
1.不管是对象字面量还是用function生成的对象,__proto__属性都一直存在
2.constructor 不是对象本身的属性(虽然可以看成是对象的属性),而是对象的__proto__属性对象中的属性
3.如果对function的原型进行重写,会修改__proto__的值,否则__proto__值不变(根据2推出constructor值不变,结果为[object Object])

继承属于js里面比较复杂的一块,因为js天生就不支持集成,这些主要是为了抚平面向对象忠实FANS们纯洁的心灵准备的,原型链继承的方式属于里面比较中规中矩的一个,而prototype和construtor又是在这种方式下比较重要的,特写此文做个总结。

本文那里还有欠妥之处,望请指教。




1
0
分享到:
评论
1 楼 achun 2011-09-05  
火狐下
alert(typeof document.constructor);
还真不是函数,是个object,我也毕竟纳闷

相关推荐

    深入分析js中的constructor和prototype

    总结一下,`constructor`是构造函数的引用,`prototype`用于定义共享的属性和方法,而`__proto__`则建立了对象实例与构造函数之间的原型链关系。理解这三个概念有助于我们更好地实现继承、封装和多态等面向对象编程...

    javascript new后的constructor属性.docx

    之后通过修改`rp.constructor`,使得`r.prototype.constructor`与`sp.constructor`相等,从而实现了对构造函数的正确引用。 #### 五、总结 通过以上分析可以看出,`constructor`属性在JavaScript中扮演着重要的...

    prototype自己做的一个例子

    在这个“prototype自己做的一个例子”中,我们将深入理解`prototype`的工作原理,以及如何利用它来实现对象间的继承。 首先,`prototype`是每个函数(在JavaScript中,函数也是对象)内置的一个属性,这个属性引用...

    javascript中类和继承(代码示例+prototype.js)

    本文将深入探讨JavaScript中的类和继承,并结合`prototype.js`文件中的示例进行解析。 ### 类的概念与模拟 在JavaScript中,我们通常使用函数来模拟类的行为。一个函数可以看作是一个类的定义,通过`new`关键字来...

    prototype 源码 注释

    `prototype.js`源码分析 ```javascript // 假设这是原型.js的一部分 function MyObject() {} // 添加一个属性到原型 MyObject.prototype.name = 'John Doe'; // 添加一个方法到原型 MyObject.prototype.sayHello...

    prototype与__proto__区别详细介绍

    - 通过`constructor.prototype`可以访问或修改构造函数的`prototype`属性。添加到`prototype`对象上的属性会被所有通过该构造函数创建的对象共享。 - `hasOwnProperty()`方法用于检查对象是否具有指定的自有属性,...

    js核心基础之构造函数constructor用法实例分析

    深入理解JavaScript的构造函数和原型模式是JavaScript编程的基础。推荐查阅《JavaScript高级程序设计》等书籍,以及相关的在线教程,以进一步掌握这些概念。 通过以上讨论,我们可以看到构造函数在JavaScript中...

    JS原型prototype和__proto__用法实例分析

    当我们创建一个函数,比如`function Foo() {}`,`Foo.prototype`实际上是一个对象,这个对象包含了默认的`constructor`属性,指向构造函数`Foo`。默认情况下,`Foo.prototype`是一个空的对象,但可以通过赋值来添加...

    前端面试题之baseJS-instanceof.zip

    如果`object`是`Constructor`的一个实例,或者`object`的原型链上存在`Constructor.prototype`,那么`instanceof`返回`true`,否则返回`false`。 1. **原型链理解**:在JavaScript中,每个对象都有一个`__proto__`...

    深入分析javascript中的错误处理机制

    UserError.prototype.constructor = UserError; throw new UserError("errorMessage"); // Uncaught UserError: errorMessage ``` 错误对象还有一个`toString()`方法,它返回`'Error:' + error对象的message属性`...

    Prototype 学习 Prototype对象

    本篇文章将深入探讨Prototype对象的核心概念与具体实现细节,帮助读者更好地理解和运用Prototype。 #### 二、Prototype对象简介 Prototype对象是该库的基础部分,它定义了一系列基本的功能和配置,为后续的高级功能...

    js prototype和__proto__的关系是什么

    在JavaScript中,prototype和__proto__是...通过上述的分析,我们可以看到prototype和__proto__在JavaScript对象继承和原型链中的重要地位和作用。理解它们之间的关系对于深入理解JavaScript的面向对象编程至关重要。

    javascript new后的constructor属性

    在JavaScript编程中,`constructor`属性是一个非常重要的特性,通常与`new`关键字一起使用。当使用`new`关键字创建一个函数的实例时,实例对象会拥有一个指向创建它的函数的`constructor`属性。这在对象创建和原型...

    prototypal-oo-js-object-oriented-constructor-functions-lab-onlin

    通过分析和运行源码,你将能够深入理解JavaScript中的原型式面向对象编程,以及如何有效地利用构造函数创建和组织代码。对于希望提升JavaScript编程技能,特别是面向对象编程方面的人来说,这是一个宝贵的资源。

    【技术分享】从浅入深 Javascript 原型链与原型链污染 .pdf

    每个对象都有一个内部属性`[[Prototype]]`,在开发环境中通常通过`__proto__`或`constructor.prototype`来访问。当试图访问对象的一个属性时,如果该对象本身没有该属性,JavaScript会沿着原型链向上搜索,直到找到...

    java script 继承的实现

    通过分析这个文件,我们可以深入理解文中提到的各种继承策略,并可能找到更高效的实现方式或扩展性的解决方案。 总的来说,理解并熟练掌握 JavaScript 的继承机制对于开发复杂的 Web 应用程序至关重要,它能够帮助...

    浅析Javascript原型继承 推荐第1/2页

    通过以上分析,我们了解到JavaScript中基于原型的继承机制,它与传统基于类的继承有所不同,但仍然提供了实现代码复用和创建复杂对象层次结构的能力。掌握原型继承对于深入理解JavaScript对象模型和设计模式至关重要...

    JavaScript 继承详解(三)

    本章节将深入分析这些常见的问题,并提出相应的解决方案。 首先,我们回顾一下使用构造函数和原型链实现继承的基本方法。在JavaScript中,我们可以通过修改构造函数的原型对象来共享属性和方法。例如,创建一个...

Global site tag (gtag.js) - Google Analytics