方式一:
function inherit(p) {
if (p == null) {
throw TypeError();
}
var t = typeof p;
if(t!=="object" && t!=="function"){
throw TypeError();
}
var o = {};
for(var prop in p){
o[prop]=p[prop];
}
return o;
}
方式二:
function inherit(p) {
if( t===null){
throw TypeError();
}
var t = typeof p;
if(t!=="object" && t!== "function"){
throw TypeError();
}
var f = function(){};
f.prototype=p;
return new f();
}
方法1只是逻辑上的原型继承,其实没有用到js的原型链机制
简而言之,区别就是:
1是
复制属性
2是
共享属性
而且1中的复制只是复制了可枚举属性。读一下ES规范就会发现:原型这种东西就是为了共享属性而设计的。
再多说一句:
通过原型共享来的属性有个特点,就是:你去读它的时候,它会到原型链上去查找;但你去写它的时候,他会在当前对象上新建一个同名属性,相当于覆盖了原型链上的同名属性。正是这个特点实现了JS面向对象的两个特性:
继承
(inherit)和重载
(override)。也就是,既可以继承祖先的共同性,又可以自定义自身的独特性。
代码@小_秦写的很多了,他的代码正是体现了两者的区别,赞一个。
第1段代码应该返回对象o
2段代码都能实现从p对象继承属性及方法,但是有些差别
这个差别就在于for(var prop in p){
的使用,其只能取出p对象中可枚举的属性,而f.prototype=p;
就没有这个问题
例如
function inherit1(p) {
if (p == null) {
throw TypeError();
}
var t = typeof p;
if(t!=="object" && t!=="function"){
throw TypeError();
}
var o = {};
for(var prop in p){
o[prop]=p[prop];
}
return o;
}
function inherit2(p) {
if( t===null){
throw TypeError();
}
var t = typeof p;
if(t!=="object" && t!== "function"){
throw TypeError();
}
var f = function(){};
f.prototype=p;
return new f();
}
function P(){
//设置属性b不可枚举
Object.defineProperty(this, 'b', { value: 2, enumerable: false });
}
P.prototype.methodA=function(){
console.log('methodA');
}
var o=inherit1(new P());
console.log(o.b);//undefined
o.methodA();//methodA
o=inherit2(new P());
console.log(o.b);//2
o.methodA();//methodA
第一段的代码有误吧? 最后居然是 return p
????
在将第一段代码中的 return p
改为 return o
后, 分析如下:
function inherit1(p) {
if (p == null) {
throw TypeError();
}
var t = typeof p;
if (t !== "object" && t !== "function") {
throw TypeError();
}
var o = {};//创建一个新的对象
for (var prop in p) {//然后将 p 中的可遍历的内容, 添加至 o 中
o[prop] = p[prop];
}
return o;//返回 新创建出来的这个对象(所以这里不是能 return p, 否则 前面的操作是无意义的)
}
function inherit2(p) {
if (t === null) {
throw TypeError();
}
var t = typeof p;
if (t !== "object" && t !== "function") {
throw TypeError();
}
var f = function() {};//创建一个空函数(当然它也是一个对象)
f.prototype = p;//修改新创建的这个函数的 prototype 指向 参数 p
return new f();//返回新创建的这个函数的 实例
}
var p = {//测试数据
x:1,
y:function(){
return this.x;
}
};
console.log('=========== test1 ==========');
var a = inherit1(p);//通过方法1 得到的结果 a
/**
上面的代码, 分解如下:
var t = {};//创建临时对象
t.x = p.x;
t.y = p.y;
var a = t;
*/
console.log(a.x, a.y(), a.hasOwnProperty('x'));//可以正常使用 p 中的x,y(但请注意 hasOwnProperty这个的结果)
a.x = 222;//尝试修改它
console.log(a.x, a.y(), a.hasOwnProperty('x'));//再次输出(请注意输出结果)
delete a.x;//删除它
console.log(a.x, a.y(), a.hasOwnProperty('x'));//再次输出(请注意输出结果)
console.log('=========== test2 ==========');
var c = inherit2(p);//通过方法1 得到的结果 c
/**
上面的代码, 分解如下:
var t = function(){};
t.prototype = p;
var c = new t();
*/
console.log(c.x, c.y(), c.hasOwnProperty('x'));//可以正常使用 p 中的x,y(但请注意 hasOwnProperty这个的结果)
c.x = 222;//尝试修改它
console.log(c.x, c.y(), c.hasOwnProperty('x'));//再次输出(请注意输出结果)
delete c.x;//删除它
console.log(c.x, c.y(), c.hasOwnProperty('x'));//再次输出(请注意输出结果)
执行结果:
=========== test1 ==========
1 1 true
222 222 true
undefined undefined false
=========== test2 ==========
1 1 false
222 222 true
1 1 false