您好,欢迎访问一九零五行业门户网

理解Javascript_06_理解对象的创建过程_javascript技巧

简单的代码
我们先来看一段简单的代码:
复制代码 代码如下:
function humancloning(){
}
humancloning.prototype ={
name:'笨蛋的座右铭'
}
var clone01 = new humancloning();
alert(clone01.name);//'笨蛋的座右铭'
alert(clone01 instanceof humancloning);//true
humancloning.prototype = {};
alert(clone01.name);//'笨蛋的座右铭'
alert(clone01 instanceof humancloning);//false
var clone02 = new humancloning();
alert(clone02.name);//undefined
alert(clone02 instanceof humancloning);//true
复杂的理论
js中只有函数对象(函数)具备类的概念,因此创建一个对象,必须使用函数对象。函数对象内部有[[construct]]方法和[[call]]方法,[[construct]]用于构造对象,[[call]]用于函数调用,只有使用new操作符时才触发[[construct]]逻辑。注:在本例中humancloning这个自定义函数是一个函数对象,那么请问object,string,number等本地对象是函数对象吗?答案是肯定的,这是因为本地对象都可以看作是函数的派生类型,在这个意义上,可以将它们跟用户定义的函数等同看待。(与《理解javascript_04_数据模型》中内置数据类型一节相呼应)
var obj=new object(); 是使用内置的object这个函数对象创建实例化对象obj。var obj={};和var obj=[];这种代码将由js引擎触发object和array的构造过程。function fn(){}; var myobj=new fn();是使用用户定义的类型创建实例化对象。
注:关于函数对象的具体概念会在后续的文章中讲解,现在可以将函数对象简单的理解为函数的概念及可.
内部的实现
结合本例,函数对象为humancloning,函数对象创建的对象实例为clone01和clone02. 现在我们来看一下var clone01 = new humancloning();的实现细节(注:函数对象的[[construct]]方法处理逻辑来负责实现对象的创建):
1. 创建一个build-in object对象obj并初始化
2. 如果humancloning.prototype是object类型,则将clone01的内部[[prototype]]设置为humancloning.prototype,否则clone01的[[prototype]]将为其初始化值(即object.prototype)
3. 将clone01作为this,使用args参数调用humancloning的内部[[call]]方法
3.1 内部[[call]]方法创建当前执行上下文(注:关于执行上下文,将在后续博文中讲解,在《javascript提速_01_引用变量优化》一文中已有部分讲解》)
3.2 调用humancloning的函数体
3.3 销毁当前的执行上下文
3.4 返回humancloning函数体的返回值,如果humancloning的函数体没有返回值则返回undefined
4. 如果[[call]]的返回值是object类型,则返回这个值,否则返回obj
注意,如下代码为步骤1,步骤2和步骤3的代码解释:
复制代码 代码如下:
var clone01 = {};
//程序外部是无法访问[[prototype]]的,仅用于理解
//clone01.[[prototype]] = humancloning.prototype;
humancloning.call(clone01);
注意步骤2中, prototype指对象显示的prototype属性,而[[prototype]]则代表对象内部prototype属性(隐式的)。构成对象prototype链的是内部隐式的[[prototype]],而并非对象显示的prototype属性。显示的prototype只有在函数对象上才有意义,从上面的创建过程可以看到,函数的prototype被赋给派生对象隐式[[prototype]]属性,这样根据prototype规则,派生对象和函数的prototype对象之间才存在属性、方法的继承/共享关系。(即原型继承实现原理,正是《理解javascript_05_原型继承原理》的内容)
注意步骤3.4中描述,让我们来看一个来自于怿飞的问题:
我想,现在回答这个问题,应该是易如反掌吧。
注:原文地址http://www.planabc.net/2008/02/20/javascript_new_function/
内存分析
一张简易的内存图,并引入的函数对象的概念,同样也解释了上面代码(相对来说图不是很严谨,但易于理解)。在此也引出了一个问题,instanceof的实现原理,想必大家也看出了一些苗头,instanceof的判断依赖于原型链,具体实现细节,请参见后续博文。
本地属性与继承属性
对象通过隐式prototype链能够实现属性和方法的继承,但prototype也是一个普通对象,就是说它是一个普通的实例化的对象,而不是纯粹抽象的数据结构描述。所以就有了这个本地属性与继承属性的问题。
首先看一下设置对象属性时的处理过程。js定义了一组attribute,用来描述对象的属性property,以表明属性property是否可以在javascript代码中设值、被for in枚举等。
obj.propname=value的赋值语句处理步骤如下:
1. 如果propname的attribute设置为不能设值,则返回
2. 如果obj.propname不存在,则为obj创建一个属性,名称为propname
3. 将obj.propname的值设为value
可以看到,设值过程并不会考虑prototype链,道理很明显,obj的内部[[prototype]]是一个实例化的对象,它不仅仅向obj共享属性,还可能向其它对象共享属性,修改它可能影响其它对象。
我们来看一个示例:
复制代码 代码如下:
function humancloning(){
}
humancloning.prototype ={
name:'笨蛋的座右铭'
}
var clone01 = new humancloning();
clone01.name = 'jxl';
alert(clone01.name);//jxl
var clone02 = new humancloning();
alert(clone02.name);//笨蛋的座右铭
结果很明确,对象的属性无法修改其原型中的同名属性,而只会自身创建一个同名属性并为其赋值。
参考。
http://www.jb51.net/article/25008.htm
其它类似信息

推荐信息