摘要:類的繼承建立繼承關系修改的指向調用父類方法調用父類的構造器調用父類上的方法封裝命名空間是沒有命名空間的,因此可以用對象模擬。參考資料面向對象
</>復制代碼
面向對象程序設計(Object-oriented programming,OOP)是一種程序設計范型,同時也是一種程序開發的方法。對象指的是類的實例。它將對象作為程序的基本單元,將程序和數據封裝其中,以提高軟件的重用性、靈活性和擴展性。——維基百科
一般面向對象包含:繼承,封裝,多態,抽象
對象形式的繼承 淺拷貝</>復制代碼
var Person = {
name: "allin",
age: 18,
address: {
home: "home",
office: "office",
}
sclools: ["x","z"],
};
var programer = {
language: "js",
};
function extend(p, c){
var c = c || {};
for( var prop in p){
c[prop] = p[prop];
}
}
extend(Person, programer);
programer.name; // allin
programer.address.home; // home
programer.address.home = "house"; //house
Person.address.home; // house
從上面的結果看出,淺拷貝的缺陷在于修改了子對象中引用類型的值,會影響到父對象中的值,因為在淺拷貝中對引用類型的拷貝只是拷貝了地址,指向了內存中同一個副本。
深拷貝</>復制代碼
function extendDeeply(p, c){
var c = c || {};
for (var prop in p){
if(typeof p[prop] === "object"){
c[prop] = (p[prop].constructor === Array)?[]:{};
extendDeeply(p[prop], c[prop]);
}else{
c[prop] = p[prop];
}
}
}
利用遞歸進行深拷貝,這樣子對象的修改就不會影響到父對象。
</>復制代碼
extendDeeply(Person, programer);
programer.address.home = "allin";
Person.address.home; // home
利用call和apply繼承
</>復制代碼
function Parent(){
this.name = "abc";
this.address = {home: "home"};
}
function Child(){
Parent.call(this);
this.language = "js";
}
ES5中的Object.create()
</>復制代碼
var p = { name : "allin"};
var obj = Object.create(o);
obj.name; // allin
Object.create()作為new操作符的替代方案是ES5之后才出來的。我們也可以自己模擬該方法:
</>復制代碼
//模擬Object.create()方法
function myCreate(o){
function F(){};
F.prototype = o;
o = new F();
return o;
}
var p = { name : "allin"};
var obj = myCreate(o);
obj.name; // allin
目前,各大瀏覽器的最新版本(包括IE9)都部署了這個方法。如果遇到老式瀏覽器,可以用下面的代碼自行部署。
</>復制代碼
if (!Object.create) {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
類的繼承
Object.create()
</>復制代碼
function Person(name, age){}
Person.prototype.headCount = 1;
Person.prototype.eat = function(){
console.log("eating...");
}
function Programmer(name, age, title){}
Programmer.prototype = Object.create(Person.prototype); //建立繼承關系
Programmer.prototype.constructor = Programmer; // 修改constructor的指向
調用父類方法
</>復制代碼
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.headCount = 1;
Person.prototype.eat = function(){
console.log("eating...");
}
function Programmer(name, age, title){
Person.apply(this, arguments); // 調用父類的構造器
}
Programmer.prototype = Object.create(Person.prototype);
Programmer.prototype.constructor = Programmer;
Programmer.prototype.language = "js";
Programmer.prototype.work = function(){
console.log("i am working code in "+ this.language);
Person.prototype.eat.apply(this, arguments); // 調用父類上的方法
}
封裝
命名空間
js是沒有命名空間的,因此可以用對象模擬。
</>復制代碼
var app = {}; // 命名空間app
//模塊1
app.module1 = {
name: "allin",
f: function(){
console.log("hi robot");
}
};
app.module1.name; // "allin"
app.module1.f(); // hi robot
靜態成員
</>復制代碼
function Person(name){
var age = 100;
this.name = name;
}
//靜態成員
Person.walk = function(){
console.log("static");
};
Person.walk(); // static
私有與公有
</>復制代碼
function Person(id){
// 私有屬性與方法
var name = "allin";
var work = function(){
console.log(this.id);
};
//公有屬性與方法
this.id = id;
this.say = function(){
console.log("say hello");
work.call(this);
};
};
var p1 = new Person(123);
p1.name; // undefined
p1.id; // 123
p1.say(); // say hello 123
模塊化
</>復制代碼
var moduleA;
moduleA = function() {
var prop = 1;
function func() {}
return {
func: func,
prop: prop
};
}(); // 立即執行匿名函數
prop,func 不會被泄露到全局作用域。或者另一種寫法,使用 new
</>復制代碼
moduleA = new function() {
var prop = 1;
function func() {}
this.func = func;
this.prop = prop;
}
多態
模擬方法重載
arguments屬性可以取得函數調用的實參個數,可以利用這一點模擬方法的重載。
</>復制代碼
function demo(a, b ){
console.log(demo.length); // 得到形參個數
console.log(arguments.length); //得到實參個數
console.log(arguments[0]); // 第一個實參 4
console.log(arguments[1]); // 第二個實參 5
}
demo(4, 5, 6);
</>復制代碼
//實現可變長度實參的相加
function add(){
var total = 0;
for( var i = arguments.length - 1; i >= 0; i--){
total += arguments[i];
}
return total;
}
console.log(add(1)); // 1
console.log(add(1, 2, 3)); // 7
// 參數不同的情況
function fontSize(){
var ele = document.getElementById("js");
if(arguments.length == 0){
return ele.style.fontSize;
}else{
ele.style.fontSize = arguments[0];
}
}
fontSize(18);
console.log(fontSize());
// 類型不同的情況
function setting(){
var ele = document.getElementById("js");
if(typeof arguments[0] === "object"){
for(var p in arguments[0]){
ele.style[p] = arguments[0][p];
}
}else{
ele.style.fontSize = arguments[0];
ele.style.backgroundColor = arguments[1];
}
}
setting(18, "red");
setting({fontSize:20, backgroundColor: "green"});
方法重寫
</>復制代碼
function F(){}
var f = new F();
F.prototype.run = function(){
console.log("F");
}
f.run(); // F
f.run = function(){
console.log("fff");
}
f.run(); // fff
抽象類
在構造器中 throw new Error(""); 拋異常。這樣防止這個類被直接調用。
</>復制代碼
function DetectorBase() {
throw new Error("Abstract class can not be invoked directly!");
}
DetectorBase.prototype.detect = function() {
console.log("Detection starting...");
};
DetectorBase.prototype.stop = function() {
console.log("Detection stopped.");
};
DetectorBase.prototype.init = function() {
throw new Error("Error");
};
// var d = new DetectorBase();// Uncaught Error: Abstract class can not be invoked directly!
function LinkDetector() {}
LinkDetector.prototype = Object.create(DetectorBase.prototype);
LinkDetector.prototype.constructor = LinkDetector;
var l = new LinkDetector();
console.log(l); //LinkDetector {}__proto__: LinkDetector
l.detect(); //Detection starting...
l.init(); //Uncaught Error: Error
參考資料
JavaScript 面向對象
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/90832.html
摘要:了解面向對象編程之前,首先要了解的執行順序。的解析過程分為兩個階段預處理階段與執行期。在執行階段的執行上下文對象由賦值為指向對應函數 了解js面向對象編程之前,首先要了解js的執行順序。js的解析過程分為兩個階段:預處理階段與執行期。 預處理階段 在預處理階段,js會首先創建一個執行上下文對象(Execute Context,然后掃描聲明式函數和用var定義的變量,將其加入執行上下文環...
摘要:構造函數通常首字母大寫,用于區分普通函數。這種關系常被稱為原型鏈,它解釋了為何一個對象會擁有定義在其他對象中的屬性和方法。中所有的對象,都有一個屬性,指向實例對象的構造函數原型由于是個非標準屬性,因此只有和兩個瀏覽器支持,標準方法是。 從這篇文章開始,復習 MDN 中級教程 的內容了,在初級教程中,我和大家分享了一些比較簡單基礎的知識點,并放在我的 【Cute-JavaScript】系...
摘要:在構造函數中的中定義的屬性和方法,會被創建的對象所繼承下來。從上面的輸出結果看出,指向了其構造函數的,而本身也是一個對象,其內部也有屬性,其指向的是直到最后指向,這條原型鏈才結束。和都指向,說明原型鏈到終止。 prototype原型對象 每個函數都有一個默認的prototype屬性,其實際上還是一個對象,如果被用在繼承中,姑且叫做原型對象。 在構造函數中的prototype中定義的屬性...
摘要:的變量作用域是基于其特有的作用域鏈的。需要注意的是,用創建的函數,其作用域指向全局作用域。所以,有另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。 作用域 定義 在編程語言中,作用域控制著變量與參數的可見性及生命周期,它能減少名稱沖突,而且提供了自動內存管理 --javascript 語言精粹 我理解的是,一個變量、函數或者成員可以在代碼中訪問到的范圍。 js的變量作...
摘要:對構造函數使用運算符,就能生成實例,并且變量會綁定在實例對象上。這個對象的所有屬性和方法,都會被構造函數的實例繼承。 對象 對象的含義 所謂對象,就是一種無序的數據集合,由若干個鍵值對(key-value)構成。 對象的創建 使用new運算符創建Object var p = new Object(); p.name = Tony; 使用對象字面量的形式 //對象字面量形...
閱讀 2271·2021-10-09 09:41
閱讀 3426·2021-09-13 10:34
閱讀 1934·2019-08-30 12:59
閱讀 571·2019-08-29 17:27
閱讀 1070·2019-08-29 16:07
閱讀 2964·2019-08-29 13:15
閱讀 1316·2019-08-29 13:14
閱讀 1571·2019-08-26 12:18