构造函数能生成实例,又有prototype属性,就成了继承的好帮手。
不用构造函数,js生成对象还有一种更方便的方式,字面量。第一章中的例子;
/*字面量*/var jim = {};jim.name = "Jim";jim.sayHello = function(){alert(this.name);};var hanmeimei = { name:"hanmeimei", sayHello:function(){alert(this.name);}};
不构造函数,我们如何继承?
(一)浅复制
我们可以继承父母的基因,也可以像兄弟姐妹朋友们学习喽,任何人都可以。我们完全可以直接继承一个对象,通过下面的方法:
function extendCopy(p, c){ var c = c || {}; for(var i in p){ c[i]=p[i]; } return c; }
这段代码也非常实用,早起的jQuery,Prototype都有这种实现
var jim = {};jim.name = "Jim";jim.sayHello = function(){alert(this.name);};/*var hanmeimei = { name:"hanmeimei", sayHello:function(){alert(this.name);}};*/var hanmeimei = extendCopy(jim);hanmeimei.name = "hanmeimei";hanmeimei.sayHello();
(二)深复制
上面的复制函数有个潜在的问题
如果被继承的对象有一个属性 是数组对象/等引用变量,而不是值变量,继承对象中的这个属性,也指向那个变量的,他们共享了数组、方法,这往往不是我们希望的。
如:
var a = { numbers:[1,2,3], letters:['a','b'], obj:{prop:1}, x:1};var b = extentdCopy(a);
这种情形下,对象a 和 b的numbers/letters/obj 属性是共享的,如果我们修改b.numbers, a.numbers也就变了,这不是我们想要的
我们不能通过简单的 b.numbers = a.numbers 实现根本的复制。
怎么办呢?可以空过递归实现,看以下代码:
function deepCopy(p, c){ var c = c || {}; for(var i in p){ if(type of p[i] === 'object'){ c[i] = (p[i].constructor === Array) ? [] : {}; deepCopy(p[i], c[i]); } else { c[i] = p[i]; } }}
这样,继承元素 和 被继承元素 就不会有共享的属性了,只有方法是共享的,属性都是重建的,这样就解决了上面 a 和 b 继承的问题
(三)object(o)
我们还有一种快捷的方式,生成一个共享方法的新对象:就是把父“对象”当做prototype,通过临时构造函数生成一个新对象。
对象虽然是在函数内部用构造函数生成的,但是从外部看,我们的确是用一个对象产生了一个新的对象:
function object(o){ function F(){}; F.prototype = o; return new F();}
似成相识吧
var jim = {};jim.name = "Jim";jim.sayHello = function(){alert(this.name);};/*var hanmeimei = { name:"hanmeimei", sayHello:function(){alert(this.name);}};var hanmeimei = extendCopy(jim);hanmeimei.name = "hanmeimei";hanmeimei.sayHello();*/var hanmeimei = object(jim);hanmeimei.name = "hanmeimei";hanmeimei.sayHello();
优缺点不再赘述,和上一章节一样:链式的继承 扁平的继承 各有千秋
(四)一、三方式的混杂模式,通过(三)继承对象,通过(一)扩展对象
function objectPlus(o, stuff){ var n = object(o); extendCopy(n,stuff); return n;}
通过(一)(二)(三) 可以衍生出很多对象继承的方法:
多重继承:
function multi(){ var n = {}, stuff, j = 0, len = arguments.length; for (j = 0; j < len; j++){ stuff = arguments[j]; extendCopy(n,stuff); } return n;}
这种方式实现的多重继承缺点很明显。其实前后两篇文章中介绍的方式都各有缺点,结合自己的需要改善即可。
聪明的你,读到这里,也许已经弄清继承的基本思路。后面一篇文章来个大汇总。