Ⅰ js class繼承問題,希望new出子類的時候自動調用從父類繼承來的方法
1.把父類的這個方法改成private 2.如果是需要一個子類可以其它子類不可以的話,那你就要考慮這樣的繼承是否合理了。 3.如果覺得合理並且有這鍾需要的話,方法一:在父類前面不要加任何修飾符。然後子類和調用類移到 其它包里 。方法二:空方法(取巧的做法)
Ⅱ 在js中,子類如何調用父類中方法如下圖示:
//子類Student
function Student(name,age,sex,phone){
//繼承方法
Person.call(this,name,age);
//添加自己的屬性
this.sex=sex;
this.phone=phone;
//添加自己的方法
this.say();
}
//繼承父類的屬性
for(var i in Person.prototype){
Student.prototype[i]=Person.prototype[i];
}
//重寫父類方法
Student.prototype.say()
{
alert(this.phone+' 'this.sex);
}
Ⅲ javascript實現繼承有哪些方式
Javascript的繼承在很多書裡面細致的分了很多種類型和實現方式,大體上就是兩種:對象冒充、原型方式。這兩種方式各有優點和缺陷,這里我給你先列舉出來,再從底層分析區別:
(一)對象冒充
function A(name){
this.name = name;
this.sayHello = function(){alert(this.name+」 say Hello!」);};
}
function B(name,id){
this.temp = A;
this.temp(name); //相當於new A();
delete this.temp; //防止在以後通過temp引用覆蓋超類A的屬性和方法
this.id = id;
this.checkId = function(ID){alert(this.id==ID)};
}
當構造對象B的時候,調用temp相當於啟動A的構造函數,注意這里的上下文環境中的this對象是B的實例,所以在執行A構造函數腳本時,所有A的變數 和方法都會賦值給this所指的對象,即B的實例,這樣子就達到B繼承了A的屬性方法的目的。之後刪除臨時引用temp,是防止維護B中對A的類對象(注 意不是實例對象)的引用更改,因為更改temp會直接導致類A(注意不是類A的對象)結構的變化。
我們看到了,在Js版本更新的過程中,為了更方便的執行這種上下文this的切換以達到繼承或者更加廣義的目的,增加了call和apply函數。它們的 原理是一樣的,只是參數不同的版本罷了(一個可變任意參數,一個必須傳入數組作為參數集合)。這里就以call為例子,解釋一下用call實現的對象冒充 繼承。
function Rect(width, height){
this.width = width;
this.height = height;
this.area = function(){return this.width*this.height;};
}
function myRect(width, height, name){
Rect .call(this,width,height);
this.name = name;
this.show = function(){
alert(this.name+」 with area:」+this.area());
}
}
關於Call方法,官方解釋:調用一個對象的一個方法,以另一個對象替換當前對象。
call (thisOb,arg1, arg2…)
這也是一種對象冒充的繼承,其實在call方法調用的時候發生的事情也是上下文環境變數this的替換,在myRect函數體中this肯定是指向類 myRect對象的實例了,然而用這個this作為上下文環境變數調用名字叫Rect方法,即類Rect的構造函數。於是此時調用Rect時候對this 的賦值屬性和方法都實際上是對一個myRect的對象進行。所以說盡管call和apply並不是僅僅為了繼承而新增的方法,但用它們可以模擬繼承。
對象冒充繼承就是這么一回事,它可以實現多重繼承,只要重復做這一套賦值的流程就可以了。不過目前真正大規模使用得並不多,為什麼呢?因為它有一個明顯的 性能缺陷,這就要說道OO的概念了,我們說對象是成員+成員方法的集合,構造對象實例的時候,這些實例只需要擁有各自的成員變數就可以了,成員方法只是一 段對變數操作的可執行文本區域而已,這段區域不用為每個實例而復制一份,所有的實例都可以共享。現在回到Js利用對象冒充模擬的繼承里,所有的成員方法都 是針對this而創建的,也就是所所有的實例都會擁有一份成員方法的副本,這是對內存資源的一種極度浪費。其它的缺陷比如說對象冒充無法繼承 prototype域的變數和方法就不用提了,筆者認為前一個致命缺陷就已經足夠。不過,我們還是需要理解它,特別是父類的屬性和方法是如何繼承下來的原 理,對於理解Js繼承很重要。
(二)原型方式
第二種繼承方式是原型方式,所謂原型方式的繼承,是指利用了prototype或者說以某種方式覆蓋了prototype,從而達到屬性方法復制的目的。 其實現方式有很多中,可能不同框架多少會有一點區別,但是我們把握住原理,就不會有任何不理解的地方了。看一個例子(某一種實現):
function Person(){
this.name = 「Mike」;
this.sayGoodbye = function(){alert(「GoodBye!」);};
}
Person.prototype.sayHello = function(){alert(」Hello!」);};
function Student(){}
Student.prototype = new Person();
關鍵是對最後一句Student原型屬性賦值為Person類構造的對象,這里筆者解釋一下父類的屬性和方法是如何到子類上的。Js對象在讀取某 個對象屬性的時候,總是先查看自身域的屬性列表,如果有就返回否則去讀取prototype域(每個對象共享構造對象的類的prototype域所有屬性 和方法),如果找到就返回,由於prototype可以指向別的對象,所以Js解釋器會遞歸的去查找prototype域指向對象的prototype 域,直到prototype為本身,查找變成了一種循環,就停止,此時還沒找到就成undefined了。
這樣看來,最後一句發生的效果就是將父類所有屬性和方法連接到子類的prototype域上,這樣子類就繼承了父類所有的屬性和方法,包括name、 sayGoodbye和sayHello。這里與其把最後一句看成一種賦值,不如理解成一種指向關系更好一點。這種原型繼承的缺陷也相當明顯,就是繼承時 父類的構造函數時不能帶參數,因為對子類prototype域的修改是在聲明子類對象之後才能進行,用子類構造函數的參數去初始化父類屬性是無法實現的, 如下所示:
function Person(name){
this.name = name;
}
function Student(name,id){
this.id = id;
}
Student.prototype = new Person(this.name);
兩種繼承方式已經講完了,如果我們理解了兩種方式下子類如何把父類的屬性和方法「抓取」下來,就可以自由組合各自的利弊,來實現真正合理的Js繼承。下面是個人總結的一種綜合方式:
function Person(name){
this.name = name;
}
Person.prototype.sayHello = function(){alert(this.name+「say Hello!」);};
function Student(name,id){
Person.call(this,name);
this.id = id;
}
Student.prototype = new Person();
Student.prototype.show = function(){
alert(「Name is:」+ this.name+」 and Id is:」+this.id);
}
總結就是利用對象冒充機制的call方法把父類的屬性給抓取下來,而成員方法盡量寫進被所有對象實例共享的prototype域中,以防止方法副本重復創 建。然後子類繼承父類prototype域來抓取下來所有的方法。如想徹底理清這些調用鏈的關系,推薦大家多關注Js中prototype的 constructor和對象的constructor屬性,這里就不多說了。
Ⅳ javascript有哪些方法能夠實現繼承
JavaScript中要實現繼承,其實就是實現三層含義:
1、子類的實例可以共享父類的方法;
2、子類可以覆蓋父類的方法或者擴展新的方法;
3、子類和父類都是子類實例的「類型」。
JavaScript中,並不直接從語法上支持繼承,但是可以通過模擬的方法來實現繼承,以下是關於實現繼承的幾種方法的總結:
1、構造繼承法
2、原型繼承法
3、實例繼承法
4、拷貝繼承法
1、構造繼承法:
在子類中執行父類的構造函數。
1<SCRIPT LANGUAGE="JavaScript">
2 <!--
3 function dwn(s)
4 {
5 document.write(s+'<br/>');
6 }
7
8 //定義一個Collection類型
9 function Collection(size)
10 {
11 this.size = function(){return size}; //公有方法,可以被繼承
12 }
13
14 //定義一個_Collection類型
15 function _Collection(_size)
16 {
17 this._size = function(){return _size}; //公有方法,可以被繼承
18 }
19
20 Collection.prototype.isEmpty = function() //靜態方法,不能被繼承
21 {
22 return this.size() == 0;
23 }
24
25 //定義一個ArrayList類型,它「繼承」Colleciton類型
26 function ArrayList()
27 {
28 var m_elements = []; //私有成員,不能被繼承
29 m_elements = Array.apply(m_elements,arguments);
30
31 //ArrayList類型繼承Colleciton
32 this.base = Collection;
33 this.base.call(this,m_elements.length);
34
35 this.base = _Collection; //可以實現多態繼承
36 this.base.call(this,m_elements.length);
37
38 this.add = function()
39 {
40 return m_elements.push.apply(m_elements,arguments);
41 }
42
43 this.toArray = function()
44 {
45 return m_elements;
46 }
47 }
48
49 ArrayList.prototype.toString = function()
50 {
51 return this.toArray().toString();
52 }
53
54 //定義一個SortedList類型,它繼承ArrayList類型
55 function SortedList()
56 {
57 //SortedList類型繼承ArrayList
58 this.base = ArrayList;
59 this.base.apply(this,arguments);
60
61 this.sort = function()
62 {
63 var arr = this.toArray();
64 arr.sort.apply(arr,arguments);
65 }
66 }
67
68 //構造一個ArrayList
69 var a = new ArrayList(1,2,3);
70 dwn(a); //1,2,3
71 dwn(a.size()); //3 a從Collection繼承了size()方法
72 dwn(a.isEmpty); //undefined 但是a沒有繼承到isEmpty()方法
73
74 dwn(a._size()); //3 可以實現多態繼承
75
76 //構造一個SortedList
77 var b = new SortedList(3,1,2);
78 dwn(b.toArray());
79 b.add(4,0); //b 從ArrayList繼承了add()方法
80 dwn(b.toArray()); //b從ArrayList繼承了toArray()方法
81 b.sort(); //b自己實現sort()方法
82 dwn(b.toArray());
83 dwn(b);
84 dwn(b.size()); //b從Collection繼承了size()方法
85 //-->
86 </SCRIPT>
2、原型繼承法:
JavaScript是一種基於原型的語言。
要了解什麼是「原型繼承法」,先了解一下prototype的特性:prototype的最大特性是能夠讓對象實例共享原型對象的屬性,因此如果把某個對
象作為一個類型的原型,那麼我們說這個類型的所有實例都一這個對象為原型。這個時候,實際上這個對象的類型也可以作為那些以這個對象為原型的實例的類型。
假如:Point類的對象作為Point2D類型的原型(Point2D.prototype = new
Point(2)),那麼說Point2D的所有實例都是以Point類的對象為原型。此時,實際上Point類就可以作為Point2D類型的對象的類
型(相當於Point2D類型「繼承」了Point類型)。
見例:
1 <SCRIPT LANGUAGE="JavaScript">
2 <!--
3 function dwn(s)
4 {
5 document.write(s+"<br/>");
6 }
7
8 function Point(dimension) //定義一個Point類
9 {
10 this.dimension = dimension;
11 }
12
13 Point.prototype.distance = function() //靜態方法,可以被繼承
14 {
15 return this.dimension*2;
16 }
17
18 function Point2D(x,y) //定義一個Point2D類
19 {
20 this.x = x;
21 this.y = y;
22 }
23
24 Point2D.prototype = new Point(2); //運行「原型繼承法」使Point2D繼承Point
25
26 function Point3D(x,y,z) //定義Point3D類
27 {
28 this.x = x;
29 this.y = y;
30 this.z = z;
31 }
32
33 Point3D.prototype = new Point(3); //Point3D繼承Point類
34
35 var p2 = new Point2D(1,2); //構造一個Point2D對象
36
37 var p3 = new Point3D(1,2,3); //構造一個Point3D對象
38
39 dwn(p2.dimension); //2
40 dwn(p3.dimension); //3
41 dwn(p2.distance()); //4 可以繼承靜態方法
42 dwn(p3.distance()); //6 可以繼承靜態方法
43
44 dwn(p2 instanceof Point2D); //p2是Point2D對象
45 dwn(p2 instanceof Point); //Point2D繼承Point,p2是Point對象
46
47 dwn(p3 instanceof Point3D); //p3是Point3D對象
48 dwn(p3 instanceof Point); //Point3D繼承Point,p3是Point對象
49
50 //-->
51 </SCRIPT>
3、實例繼承法
構造繼承法和原型繼承法各有各的缺點,如:
構造繼承法沒有辦法繼承類型的靜態方法,因此它無法很好的繼承JavaScript的核心對象。
原型繼承法雖然可以繼承靜態方法,但是依然無法很好地繼承核心對象中的不可枚舉方法。
其中,javascript核心對象包括:
Array 表述數組。
Boolean 表述布爾值。
Date 表述日期。
Function 指定了一個可編譯為函數的字元串 JavaScript 代碼。
Math 提供了基本的數學常量和函數;如其 PI 屬性包含了π的值。
Number 表述實數數值。
Object 包含了由所有 JavaScript 對象共享的基本功能。
RegExp 表述了一個正則表達式;同時包含了由所有正則表達式對象的共享的靜態屬性。
String 表述了一個 JavaScript 字元串。
(1)構造繼承法的局限性:
1 <SCRIPT LANGUAGE="JavaScript">
2 <!--
3 function MyDate()
4 {
5 this.base = Date;
6 this.base.apply(this,arguments);
7 }
8
9 var date = new MyDate();
10 alert(date.toGMTSring()); //對象不支持此方法或屬性
11 //核心對象(Date)的某些方法不能被構造繼承,原因是核心對象並不像我們自定義的一般對象那樣在構造函數里進行賦值或初始化操作。
12 //-->
(2)原型繼承的局限性
1 <SCRIPT LANGUAGE="JavaScript">
2 <!--
3 function MyDate()
4 {
5
6 }
7 MyDate.prototype = new Date();
8 var date = new MyDate();
9 alert(date.toGMTSring()); //'[object]不是日期對象'
10 //-->
11 </SCRIPT>
以上說明了「構造繼承法」和「原型繼承法」的局限性(局限之一:不能很好的繼承核心對象),下面介紹如何用實例繼承法來繼承核心對象。
在介紹之前首先了解以下關於構造函數:
構造函數通常沒有返回值,它們只是初始化由this值傳遞進來的對象,並且什麼也不返回。如果函數有返回值,被返回的對象就成了new表達式的值。
1 <SCRIPT LANGUAGE="JavaScript">
2 <!--
3 function dwn(s)
4 {
5 document.write(s+'<br/>');
6 }
7 function MyDate()
8 {
9 var instance = new Date(); //instance是一個新創建的日期對象
10 instance.printDate = function() //對日期對象instance擴展printDate()方法
11 {
12 dwn(instance.toLocaleString());
13 }
14 return instance; //將instance作為構造函數的返回值返回
15 }
16
17 var date = new MyDate();
18 dwn(date.toGMTString());
19 date.printDate();
20 dwn(date instanceof MyDate); //false
21 dwn(date instanceof Date); //true
22 //對象的構造函數將會是實際構造的對象的構造函數(new Date()),而不是類型本身的構造函數(new MyDate())
23 //-->
24 </SCRIPT>
4、拷貝繼承法
拷貝繼承法是通過對象屬性的拷貝來實現繼承。
1 <script language="JavaScript">
2 function Point(dimension)
3 {
4 this.dimension = dimension;
5 }
6
7 var Point2D = function(x,y)
8 {
9 this.x = x;
10 this.y = y;
11 }
12
13 Point2D.extend = function()
14 {
15 var p = new Point(2);
16 for(var each in p) //將對象的屬性進行一對一的復制。
17 {
18 //this[each] = p[each];
19 this.prototype[each] = p[each];
20 }
21 }
22 Point2D.extend();
23 //alert(Point2D.dimension);
24 alert(Point2D.prototype.dimension);
25 </script>
Ⅳ js中繼承怎麼理解,為什麼要用js繼承
js中繼承跟java中的繼承不太一樣,一般通過call()和apply()兩種方式完成,js中的繼承是以復制的形式完成的,復制一個父對象,而不像java中直接繼承父對象,還有通過原型的方式完成繼承,也有弊端,總之js中的繼承只是形式上的對面向對象語言的一種模仿,本質上不是繼承,但用起來效果是一樣的
至於為什麼要繼承:通常在一般的項目里不需要,因為應用簡單,但你要用純js做一些復雜的工具或框架系統就要用到了,比如webgis、或者js框架如jquery、ext什麼的,不然一個幾千行代碼的框架不用繼承得寫幾萬行,甚至還無法維護