2013-09-30 2 views
0

최근 실험을 위해 new 대신 Object.create()로 전환했습니다. classA ->classA's parent ->classA's parent's parent 등과 같이 다중 상속을 얻으려면 어떻게해야합니까?Object.create chaining inheritance

예 : 아직 인사를 할 수

var test = Object.create(null); 
test.prototype = { 
    greet: function() { 
     console.info('hello world'); 
    }, 

    name: 'myName' 
}; 

var test2 = Object.create(test.prototype); 
test2.prototype = { 
    name: 'newName' 
}; 

var test3 = Object.create(test2.prototype); 
test3.prototype = { 
    name: 'another Name' 
}; 

test2 동안 우리가 test 따라서 어떠한 인사 정보를 가지고하지 않습니다 test2의 프로토 타입을 사용하기 때문에, test3 분명하지 않다.

몇 가지 기사를 읽고 상속을 위해 __proto__을 사용하는 것이 좋습니다. 올바른 javascripty 방법은 무엇입니까? Object.create 목적으로 다음하지만 Object.create

test2.prototype = new test(); 
test2.constructor = test2; 

test3.prototype = new test2(); 
test3.constructor = test3; 

var a = new test3(); 
a.greet(); 
+2

참조 http://stackoverflow.com/questions/2709612/using-object-create-instead-of-new – mccainz

+1

기술적으로 말해서 null을 상속하므로 객체가 테스트되지 않습니다. JavaScript의 객체에는 hasOwnProperty가 있어야하지만 테스트에는 포함되지 않습니다. 다른 사람들이 당신의 코드를 사용한다면 테스트가 JS 객체라고 기대할 수 있습니다. 다음과 같이 작성하십시오 :'test = Object.create (Object.prototype);' – HMR

답변

1

가 서로 직접 하나를 상속

뭔가처럼 prototype 속성은에는 역할이 없습니다. 첫 번째 예제에서는 이전에 수행했던 작업과 가장 가까운 형식으로 항목을 작성했지만 Object.create를 호출 할 때 개체의 속성을 설정할 필요가 없습니다. 통화 후에도 문제없이 설정할 수 있습니다 (두 번째 예 참조). (No 재산권 기술자와)

var test1 = Object.create(null, { 
    greet : {value : function() { 
     console.info('hello world'); 
    }}, 

    name : {value : 'myName'} 
}); 

var test2 = Object.create(test1, { 
    name : {value : 'alteredProperty'}}); 

var test3 = Object.create(test2); 

test3.greet(); // hello world 
console.log(test3.name); // alteredProperty 

간단한 예 : HMR는 지적

var test1 = Object.create(null); 
test1.greet = function() { 
    console.info('hello world'); 
}; 
test1.name = 'myName'; 

var test2 = Object.create(test1); 
test2.name = 'alteredProperty'; 

var test3 = Object.create(test2); 

test3.greet(); 
console.log(test3.name); 

때마다 당신은 test1 객체가 새 greet 기능을 만듭니다하고 그 바람직하지 않다. 다음 예제는 프로토 타입과 같은 객체에 메소드를 오프로드하여이 문제를 해결합니다.

// proto object 
var Test1 = { 
    greet : function() { console.info('hello world ' + this.name); }, 
    name : 'Test1' 
}; 

// instance of Test1 
var test1 = Object.create(Test1); 

// proto object inheriting from Test1 
var Test2 = Object.create(Test1) 
Test2.name = 'Test2'; 

// instance of Test2 
var test2 = Object.create(Test2); 

// proto object inheriting from Test2 
var Test3 = Object.create(Test2); 
Test3.size = 'big'; 


// instance of Test3 
var test3 = Object.create(Test3); 

test3.greet(); // hello world Test2 
console.info(test3.name); // Test2 
console.info(test3.size); // big 
test3.name = 'Mike'; 
test3.greet(); // hello world Mike 

위에서 볼 수 있듯이 예제는 위와 매우 유사하지만 일부 개체를 처리하는 방법이 다릅니다. 객체 중 일부 (대문자가있는 객체)는 프로토 타입이있는 생성자와 비슷하게 작동합니다. 일반적으로 직접 사용되지는 않으며 내장 객체에 대한 메서드와 기본값이 들어 있습니다. "클래스"의 인스턴스와 "클래스"를 상속하는 인스턴스가 완전히 동일한 구문을 가지기 때문에 이것은 순전히 일반적인 것입니다. proto 오브젝트가 오용되지 않도록하는 것은 사용자의 몫입니다. Object.create에게 Tibos이 같은 모습은 반환 된 객체의 prototype에 객체로 건네의 모든 구성원을 놓을 게요 않는 방법을 사용

function isInstanceOf(child, parent) { 
    return Object.prototype.isPrototypeOf.call(parent, child); 
} 

console.info(isInstanceOf(test3, Test3)); // true 
console.info(isInstanceOf(test3, Test1)); // true 
console.info(isInstanceOf(test2, Test3)); // false 
+1

이유가없는 downvotes는 쓸모가 없습니다. 이유를 제공해주세요. 실수로 배울 수 있고 다시하지 않을 수 있습니다. – Tibos

+1

아니지만 난 donwvoted 귀하의 코드는 인스턴스가 만들어 질 때마다 기능을 만듭니다. 당신은 프로토 타입을 사용하지 않고 있습니다. 나는 개인적으로 추가 CPU와 메모리를 사용하기 때문에 좋은 이유가 없기 때문에 개인적으로 좋아하지 않는다. "새로운 키워드를 좋아하지 않는다."나는 Douglas Crockford가 JS에 관해 뭐라고하는지 많이 좋아하지만 최근에 생각하지 못했다고 생각한다. 프로토 타입을 위해'new'를 사용합니다. 오래된 JS를 가지고 있다면 좋은 부분 책은 여전히 ​​거기에 몇 가지 물건을 가지고있다. 그는 오늘 동의하지 않을 것이다. – HMR

+0

@HMR 조언 해 주셔서 감사합니다. 대답은 "할 수있는 일"에 초점이 맞춰져있었습니다. "각 인스턴스의 기능"문제를 해결해야하는 권장 사항을 추가하겠습니다. – Tibos

0

: 보너스

. 우리는 위의 코드에서 보듯이

// in firefox firebug running 
// an empty page 
var Definition = { 
    name : 'Test1' 
}; 
//doesn't matter where it's defined 
Definition.greet=function() { 
    console.log(this);//<-what is this in Chrome? 
}; 
Definition.arr=[]; 
// instance of Test1 
var test1 = Object.create(Definition); 
var test2 = Object.create(Definition); 
console.log(test1.greet===test2.greet);//true 
delete test2.greet 
delete test2.greet 
delete test2.greet 
delete test2.greet//can't delete it 
test2.greet(); 
console.log(test1.greet===test2.greet);//true 
console.log(test1.arr===test2.arr);//true 
test1.arr.push(1); 
console.log(test2.arr);//=[1] 
var things=[]; 
for(thing in test1){ 
    things.push(thing); 
} 
console.log("all things in test1:",things); 
things=[]; 
for(thing in test1){ 
    if(test1.hasOwnProperty(thing)){ 
    things.push(thing); 
    } 
} 
console.log("instance things in test1:",things);//nothing, no instance variables 

[업데이트]

는 Object.create는 인스턴스 멤버이기로의 프로토 타입과 두 번째 매개 변수에 첫 번째 매개 변수의 모든 구성원이있는 개체를 반환 . (대답은 mccainz가 댓글에 오랫동안 포함되어있었습니다) 추가 된 이점 (IE8 및 수년간 업데이트되지 않은 브라우저를 무시함)은 인스턴스 멤버에서 열거 가능하고 쓰기 가능하며 구성 가능하도록 지정할 수 있으며 getters 및 setters를 만들 수 있다는 점이 다릅니다. 할당 (instance.someprop = 22는 실제로 instance.someprop (22) 일 수 있음)처럼 작동합니다.

인스턴스 특정 멤버를 지정하려면 몇 가지 패턴을 사용할 수 있습니다. 인수는 이러한 패턴을 사용할 때 코드가 "못생긴"것처럼 보이거나 새 키워드를 사용하는 것보다 더 나빠 보이지만 개인적인 취향이므로 getters 및 setter를 만들거나 별도의 제어 기능 (열거 형, 쓰기 가능)을 사용하지 않아도됩니다. 구성 가능).

var Person={ 
    talk:function(){console.log("I'm "+this.name);} 
    //,other prototype stuff related to Person 
}; 
var userCreator={ 
    processInstanceMembers:function(o,initObj){ 
    this.createName(o,initObj.name); 
    Object.defineProperty(o,"_name",{writable:true}); 
    o.name=initObj.name; 
    }, 
    get:function(initObj,inheritFrom){ 
    var ret=Object.create(inheritFrom||Person); 
    this.processInstanceMembers(ret,initObj); 
    return ret; 
    }, 
    createName:function(o){//minimalise closure scope 
    Object.defineProperty(o,"name",{ 
     get:function(){ 
     return this._name; 
     }, 
     set:function(val){ 
     if(val.replace(/\s*/gm,"")===""){ 
      throw new Error("Name can't be empty, or only whitespaces"); 
     } 
     this._name=val; 
     }, 
     enumerable : true 
    }); 
    } 
}; 

//when creating an instance you can choose what to inherit from 
//leave it out to inherit from Person 
var u=userCreator.get({name:"Ben"}); 
u.talk(); 
u.name="Benji"; 
u.talk(); 
u.name=" ";//error, name can't be empty 

의 상속을 설정하는 부모의 새로운 인스턴스를 생성 :

var userB = { 
    init: function(nameParam) { 
     this.id = MY_GLOBAL.nextId(); 
     this.name = nameParam; 
    }, 
    sayHello: function() { 
     console.log('Hello '+ this.name); 
    } 
}; 
var bob = Object.create(userB).init("Bob"); 

추가 컨트롤을 활용보다 복잡 하나가 이것이다 :

한 패턴은 init 함수를 사용하는 것 자식이 필요하지 않은 경우이 또는 도우미 함수에 Object.create를 사용할 수 있습니다.

var Child =function(){ 
    //get Parent's INSTANCE members defined in the 
    //parent function body with this.parentInstance=... 
    Parent.apply(this,arguments); 
} 
Child.prototype=Object.create(Parent.prototype); 
Child.prototype.constructor=Child; 
Child.prototype.otherFn=function(){}; 

this이 재미있을 수 있습니다. 헬퍼 기능을 가지고 있으므로 원하지 않는 경우 Object.create를 사용할 필요가 없습니다.

+0

'this'는 메서드가 호출 된 객체입니다 (바인딩되지 않은 경우). 귀하의 예에서'Definition.greet()'=> this === 정의,'test2.greet()'=> this === test2 – Tibos

+0

@Tibos 내가 의미하는 것은 크롬이 인스턴스와 proto 상속받은 멤버를 따로 따로 보여 준다는 것입니다. 코드에서 알 수 있듯이 인스턴스 멤버가 없으므로 문제가 될 수 있습니다. 'arr' 예제를보십시오. test1 인스턴스의 값을 누르면 test2의 'arr'멤버가 변경됩니다. – HMR

+0

@Tibos 예, Chrome은 '__proto__'에 모든 멤버가있는 빈 개체를 보여줍니다. – HMR