js中继承可以分为两种:对象冒充和原型链方式
一、对象冒充包括三种:临时属性方式、call()及apply()方式
1.临时属性方式
function Person(name){
this.name = name;
this.say = function(){
alert('My name is '+this.name);
}
}
function F2E(name,id){
this.temp = Person;
this.temp(name);
delete this.temp;
this.id = id;
this.showId = function(){
alert('Good morning,Sir,My work number is '+this.id);
}
}
var simon = new F2E('Simon',9527);
simon.say();
simon.showId();
2.call()/apply()方式
实质上是改变了this指针的指向
function Person(name){
this.name = name;
this.say = function(){
alert('My name is '+this.name);
}
}
function F2E(name,id){
Person.call(this,name); //apply()方式改成Person.apply(this,new Array(name));
this.id = id;
this.showId = function(){
alert('Good morning,Sir,My work number is '+this.id);
}
}
var simon = new F2E('Simon',9527);
simon.say();
simon.showId();
缺点:先来看这么一张内存分配图:
在OO概念中,new实例化后,对象就在堆内存中形成了自己的空间,值得注意的是,这个代码段。而成员方法就是存在这个代码段的,并且方法是共用的。问题就在这里,通过对象冒充方式继承时,所有的成员方法都是指向this的,也就是说new之后,每个实例将都会拥有这个成员方法,并不是共用的,这就造成了大量的内存浪费。并且通过对象冒充的方式,无法继承通过prototype方式定义的变量和方法,如以下代码将会出错:
function Person(name){
this.name = name;
this.say = function(){
alert('My name is '+this.name);
}
}
Person.prototype.age = 20;
Person.prototype.sayAge = function(){alert('My age is '+this.age)};
function F2E(name,id){
Person.apply(this,new Array(name));
this.id = id;
this.showId = function(){
alert('Good morning,Sir,My work number is '+this.id);
}
}
var simon = new F2E('Simon',9527);
simon.sayAge(); //提示TypeError: simon.sayAge is not a function
二、原型链方式
function Person(){
this.name = 'Simon';
}
Person.prototype.say = function(){
alert('My name is '+this.name);
}
function F2E(id){
this.id = id;
this.showId = function(){
alert('Good morning,Sir,My work number is '+this.id);
}
}
F2E.prototype = new Person();
var simon = new F2E(9527);
simon.say();
simon.showId();
alert(simon.hasOwnProperty('id')); //检查是否为自身属性
接下来按照上面的例子来理解以下js原型链概念:
프로토타입 체인은 다음과 같이 이해될 수 있습니다. js의 각 개체에는 숨겨진 __proto__ 속성이 있습니다. 인스턴스화된 개체의 __proto__ 속성은 해당 클래스의 프로토타입 메서드를 가리키고 이 프로토타입 메서드는 다른 인스턴스화된 개체에 할당될 수 있습니다. 이 개체의 __proto__는 해당 클래스를 가리켜야 하며 체인을 형성해야 합니다. 즉,
F2E.prototype = new Person()
이 문장이 핵심입니다. js 객체가 특정 속성을 읽으면 먼저 자체 속성을 검색합니다. 그렇지 않은 경우 프로토타입 체인에서 객체의 속성을 검색합니다. 즉, 프로토타입 체인의 방법을 공유할 수 있어 객체 가장 및 메모리 낭비 문제를 해결할 수 있습니다.
단점에 대해 이야기해보자:
프로토타입 체인 상속은 하위 클래스를 인스턴스화할 때 매개변수를 상위 클래스에 전달할 수 없다는 것을 의미하므로 Person 함수가 없습니다. () 이 예에서는 매개변수이지만 this.name="Simon"으로 직접 작성됩니다. 다음 코드는 예상한 결과를 얻지 못합니다.
function 사람(이름){
this.name = name;
}
Person.prototype.say = function(){
Alert('내 이름은 'this.name입니다);
}
function F2E(이름,id){
this.id = id;
this.showId = function(){
Alert('안녕하세요, 선생님, 내 일입니다. number는 ' this .id);
}
}
F2E.prototype = new Person();
var simon = new F2E("Simon",9527);
simon.say( );
simon.showId();
function 사람(이름){
this.name = 이름;
}
사람 .prototype.say = function(){
Alert('내 이름은 ' this.name 입니다);
}
function F2E(name,id){
this.id = id ;
this.showId = function(){
Alert('안녕하세요, 선생님, 제 직장 번호는 'this.id입니다);
}
}
F2E.prototype = new Person( ); //여기에서는 값을 전달할 수 없습니다. this.name이나 name은 모두 작동하지 않습니다. F2E.prototype = new Person('wood')를 직접 작성할 수 있지만 이 경우 simon.say() 내 이름은 나무입니다
var simon = new F2E("Simon",9527);
simon.say(); //팝업 내 이름은 정의되지 않았습니다
simon.showId() ;
마지막으로 우리가 생각하는 상속을 구현하는 더 좋은 방법을 요약해 보겠습니다. 멤버 변수는 객체 가장을 사용하고 멤버 메서드는 프로토타입 체이닝을 사용합니다.
function Person(name){
this.name = name;
}
Person .prototype.say = function(){
Alert('제 이름은 ' this.name 입니다);
}
function F2E(name,id){
Person.call(this ,name);
this.id = id;
}
F2E.prototype = new Person()
//여기서 한 가지 세부정보를 참고하세요. F2E.prototype = new Person(); front
F2E.prototype.showId = function(){
Alert('안녕하세요, 선생님, 제 직장 번호는 'this.id);
}
var simon = new F2E("Simon",9527);
simon.say();
simon.showId();