`
achun
  • 浏览: 318792 次
  • 性别: Icon_minigender_1
  • 来自: 河南郑州
社区版块
存档分类
最新评论

固有对象和非固有对象继承的差异

阅读更多

 

这篇是 上篇 固有对象和非固有对象的成员,值类型赋值,非值型引用的差异

的继续.

首先我们这里说固有对象就是 布尔值 字符串 数值 通用对象 数组 函数 (未定义 空值 太特殊,就不提了 )

对应的对象就是 Boolean,String,Number,Object,Array,Function(这几个字母在这里指的是对象,不是指类型表示,这几个对象的类型都是 function/函数 )

 

还记得上篇中说的

无法对 值类型赋予新的可变成员

布尔值 字符串 数值  就是值类型, Boolean,String,Number 不是值类型,是function

这个绕嘴的说法都是因为文字上的写法造成的,我们用 小写 boolean,string,number (其实javascript也就是这么表示的)或中文的布尔值,字符串,数值表示类型,Boolean,String,Number表示JavaScript 的3个对象.

所以:

/*以下有效*/
Boolean.foo='foo';
String.foo='foo';
Number.foo='foo';
Object.foo='foo';
Array.foo='foo';
Function.foo='foo';
/*以下无效*/
'string'.foo='foo';
(1).foo='foo';
true.foo='foo';

 下面看看用prototype(原型定义)方法扩展对象在使用上的差别:

String.prototype.foo='foo';
var v=new String('string');
v.foo=3;
alert(v.foo);//3
var v='string';
v.foo=3;
alert(v.foo);//foo

噢,原来new这个关键字用和不用还是有差别的,同样的道理也适用于Boolean,Number,但是:

Object.prototype.foo='foo';
var v=new Object();
v.foo=3;
alert(v.foo);//3
var v={};
v.foo=3;
alert(v.foo);//3,原型都被改了
Object.prototype.foo={v:'foo'};//非值对象也同样
var v={};
v.foo.v=3;
alert(v.foo.v);//3
var v={};
alert(v.foo.v);//3,原型都被改了

进一步:

String.prototype.foo={v:'foo'};
var v=new String('string');
v.foo.v=3;
alert(v.foo.v);//3
var v='string';
alert(v.foo.v);//3,原型都被改了

值对象和非值对象就是不一样.

 

好像有些乱,我也没有找到合适的语言来组织这个

var v=new String('string');//和
var v='string';//以及
String.prototype.foo={foo:'foo'};//对JavaScript内建 string的影响到底如何描述

 

不过对于非固有对象 也就是对象 就没有那么复杂了,

var foo=function(){};
foo.prototype={v:'foo',foo:{v:'foo'}};
var o=new foo;
o.v=3;
o.foo.v=4;
var o =new foo;
alert(o.v);//foo
alert(o.foo.v);//,原型都被改了

 原因很简单,因为foo.prototype只不过由于名称的特殊,会让JavaScript对new 操作进行特殊的继承处理,除此之外,

foo.prototype也具有普通对象的特性,符合值类型拷贝副本 ,非值型引用 的规律

那容易让人迷惑的o.foo.v的v不也是值类型 么?是可是别忘了前面的foo是非值型 ,

o.foo.v  中的foo已经指向 foo.prototype.foo

当然o.foo.vfoo.prototype.foo.v同一个 对象了

 

同样道理:由于

var o=new foo;

o是foo的一个实例,是两个对象,那

o!=foo;
o!=foo.prototype;
o.v!=foo.prototype.v;//因为是值类型
o.foo===foo.prototype.foo;//非值型

非值类型就引用到同一内存对象上了.

不过非值型的赋值也有意思,就是改变的是引用,而不是单纯的改变值.

var foo=function(){};
foo.prototype={v:'foo',foo:{v:{v:'foo'}}};
var o=new foo;
o.v={};
o.foo.v={v:'new'};
var o =new foo;
alert(o.foo.v.v);//原型都被改了

 这回原型又被改了.这样

var foo=function(){};
foo.prototype={v:'foo',foo:{v:{v:'foo'}}};
var o=new foo;
o.v={};
o.foo={v:'new'};
var o =new foo;
alert(o.foo.v.v);//没有被改

一会儿改一会儿不改,到底问题在哪里,差别在哪里问题就在那里:

差别在:

o.foo={v:'new'};
o.foo.v={v:'new'};

注意o是独立的实例对象,o.foo是引用,和 foo.prototype.foo是同一个对象.直接对o.foo赋值当然改变的是引用,掐断了引用,引用到一个新的对象了,和原来的foo.prototype.foo不一样了,虽然

{v:'foo'}

也是一个对象,不过要注意o.foo.v中的foo已经明确范围 ,这个范围就是同一个对象,当然原型也被改了.回头再看看前面的o,

哈哈,原来o是个新的实例,范围不同 呀!同样适用这个确定范围的说法

说了这么多,其实就一句话,引用的问题,先 确定范围 吧,是不同的,还是相同的.

如果用标准的说法这是个Scope Chain的问题.抄一段规范的翻译文章:

http://www.cnblogs.com/winter-cn/archive/2008/07/07/1237168.html 写道
1. 获取Scope Chain的下一个对象。如果没有对象了,则转到第5步。
2. 调用结果(1)的[[HasProperty]]方法, 传递Identifier作为参数
3. 如果结果(2)是true, Reference(引用)类型的值,它的base object是结果(1)而它的
property name是Identifier
4. 跳到第1步
5. 返回一个Reference类型,它的base object是null它的property name 是Identifier.
注:Reference(引用)类型的值是JS引擎使用的一种数据类型,它分为base object和property name两个部分。假设在JS代码中有obj.prop这样的表达式,那么解释成Reference类型,base object是对象obj,而property name是字符串”prop”
 Scope Chain开始时被设为宿主对象,所以在全局代码中的变量就是宿主对象的属性。Scope Chain在执行时由JS引擎自动维护,编译型的引擎也会创建相应的运行时环境来做此事。Scope Chain一般在函数调用或者执行进入with块的时候改变。
 

说起来麻烦,用起来其实很简单.

 

还有一点是在JavaScript里继承这个词不是很准确,连祖先都随时可以被修改,这那是继承,明显是颠覆嘛!所以我觉得用Mixin

混入来说更合适,也无所谓,反正大家都知道在JavaScript里说的都是一回事.

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics