摘要:下面定義一個(gè)構(gòu)造函數(shù)不過(guò)這樣寫這個(gè)函數(shù),每個(gè)對(duì)象都會(huì)包括一部分,太浪費(fèi)內(nèi)存。原型鏈與繼承在學(xué)習(xí)原型鏈之前我們一定要區(qū)分清楚是構(gòu)造函數(shù)的屬性,而是對(duì)象的屬性。但對(duì)象形式不等于基本類型。用來(lái)判斷對(duì)象是否某個(gè)構(gòu)造函數(shù)的實(shí)例。
js是一個(gè)基于對(duì)象的語(yǔ)言,所以本文研究一下js對(duì)象和類實(shí)現(xiàn)的過(guò)程和原理。
對(duì)象的屬性及屬性特性下面是一個(gè)對(duì)象的各個(gè)部分:
var person = { name: "Lily", age: 10, work: function(){ console.log("Lily is working..."); } }; person.gender = "F"; //可以動(dòng)態(tài)添加屬性 Object.defineProperty(person, "salary", { //添加屬性 value: 10000, writable: true, //是否可寫,默認(rèn)false enumerable: true, //是否可枚舉,默認(rèn)false configuration: true //是否可配置,默認(rèn)false; }); Object.defineProperties(person, { //添加多個(gè)屬性 "father": { value: Bob, enumerable: true }, "mather": { value: Jelly, enumerable: true } }); delete person.age; // 刪除屬性 Object.getOwnPropertyDescriptor(person, "father"); //{ value:10000,writable:true,enumerable:true,configuration:true}
是否可寫指得是其值是否可修改;
是否可枚舉指的是其值是否可以被for...in...遍歷到;
是否可配置指的是其可寫性,可枚舉性,可配置性是否可修改,并且決定該屬性可否被刪除。
這是一個(gè)普通的對(duì)象和常見(jiàn)操作,不多說(shuō),下面是一個(gè)具有g(shù)et/set的對(duì)象:
var person = { _age: 11, get age(){ return this._age; }, set age(val){ this._age = val; } }; //如下方法訪問(wèn): console.log(o.age); //讀 o.age = 30; //寫 console.log(o.age);對(duì)象的特性
上文,我們只提到了對(duì)象屬性的4個(gè)性質(zhì),對(duì)象自己其實(shí)也有3個(gè)性質(zhì):
可擴(kuò)展性可不可擴(kuò)展是指一個(gè)對(duì)象可不可以添加新的屬性;Object.preventExtensions 可以讓這個(gè)對(duì)象變的不可擴(kuò)展。嘗試給一個(gè)不可擴(kuò)展對(duì)象添加新屬性的操作將會(huì)失敗,但不會(huì)有任何提示,(嚴(yán)格模式下會(huì)拋出TypeError異常)。Object.preventExtensions只能阻止一個(gè)對(duì)象不能再添加新的自身屬性,仍然可以為該對(duì)象的原型添加屬性,但__proto__屬性的值也不能修改。
var person = { name: "Lily", age: 10 }; //新創(chuàng)建的對(duì)象默認(rèn)是可擴(kuò)展的 console.log(Object.isExtensible(person)); //true person.salary = 10000; console.log(person.salary) //10000 Object.preventExtensions(person);//將其變?yōu)椴豢蓴U(kuò)展對(duì)象 console.log(Object.isExtensible(person)); //false person.height = 180; //失敗,不拋出錯(cuò)誤 console.log(person.height); //undefined person.__proto__.height = 180; //在其原型鏈上添加屬性 console.log(person.height); //180 delete person.age; //可以刪除已有屬性 console.log(person.age); //undefined person.__proto__ = function a(){}; //報(bào)錯(cuò)TypeError: #
這里如果不理解__proto__不要緊,下文會(huì)重點(diǎn)解釋這個(gè)屬性
密封性如果我們想讓一個(gè)對(duì)象即不可擴(kuò)展,又讓它的所有屬性不可配置,一個(gè)個(gè)修改屬性的configurable太不現(xiàn)實(shí)了,我們把這樣的對(duì)象叫做密封的(Sealed)。用Object.isSealed()判斷一個(gè)對(duì)象是否密封的,用Object.seal()密封一個(gè)對(duì)象。 其特性包括不可擴(kuò)展對(duì)象和不可配置屬性的相關(guān)特性。
var person = { name: "Lily", age: 10 }; //新創(chuàng)建的對(duì)象默認(rèn)是不密封的 console.log(Object.isSeal(person)); //false Object.seal(person);//將其變?yōu)槊芊鈱?duì)象 console.log(Object.isSeal(person)); //true delete person.age; //無(wú)法刪除已有屬性,失敗,不報(bào)錯(cuò)。但嚴(yán)格模式會(huì)報(bào)錯(cuò) console.log(person.age); //undefined person.__proto__ = function a(){}; //報(bào)錯(cuò)TypeError: #凍結(jié)性is not extensible(...)
此時(shí),這個(gè)對(duì)象屬性可能還是可寫的,如果我們想讓一個(gè)對(duì)象的屬性既不可寫也不可配置,同時(shí)讓該對(duì)象不可擴(kuò)展,那么就需要凍結(jié)這個(gè)對(duì)象。用Object.freeze()凍結(jié)對(duì)象,用isFrozen()判斷對(duì)象是否被凍結(jié)。由于相比上一個(gè)例子,僅僅是現(xiàn)有的變得不可寫了,這里就不舉太多例子了。
不過(guò)值得注意的是,對(duì)于具有setter的屬性一樣不可寫。
var person = { name: "Lily", _age: 10, get age(){ return this._age; }, set age(val){ this._age = val; } }; //新創(chuàng)建的對(duì)象默認(rèn)不是凍結(jié)的 console.log(Object.isFrozen(person)); //false Object.freeze(person);//將其變?yōu)椴豢蓴U(kuò)展對(duì)象 console.log(Object.isExtensible(person)); //false console.log(Object.isSealed(person)); //true console.log(Object.isFrozen(person)); //true console.log(person.name); //"Lily" person.name = "Bob"; //失敗,但不報(bào)錯(cuò),但嚴(yán)格模式會(huì)報(bào)錯(cuò)。 console.log(person.name); //"Lily" console.log(person.age); //10 person.age = 30; console.log(person.age); //10深凍結(jié)和淺凍結(jié)
深凍結(jié)和淺凍結(jié)的主要差異出現(xiàn)在可擴(kuò)展性上,所以你也可以理解為深可擴(kuò)展和淺可擴(kuò)展。我們看一下以下代碼:
var person = { addr: {} } Object.freeze(person); person.addr.province = "Guangzhou"; //淺凍結(jié):對(duì)象的屬性對(duì)象可以繼續(xù)擴(kuò)展 console.log(person.addr.province); //"Guangzhou"
為了實(shí)現(xiàn)深凍結(jié),我們寫一個(gè)函數(shù):
var person = { name: "nihao", addr: {}, family:{ slibing:{}, parents:{} } } deepFreeze(person); person.addr.province = "Guangzhou"; //深凍結(jié):對(duì)象的屬性對(duì)象無(wú)法繼續(xù)擴(kuò)展 console.log(person.addr.province); //undefined person.family.parents.father = "Bob"; //深凍結(jié):對(duì)象的屬性對(duì)象無(wú)法繼續(xù)擴(kuò)展 console.log(person.family.parents.father); //undefined function deepFreeze(obj){ Object.freeze(obj); for(key in obj){ if(!obj.hasOwnProperty(key)) continue; if(obj[key] !== Object(obj[key])) continue; deepFreeze(obj[key]); //遞歸調(diào)用 } }
注意,這里遞歸沒(méi)有判斷鏈表是否成環(huán),判斷有環(huán)鏈表是數(shù)據(jù)結(jié)構(gòu)的知識(shí),可以使用一組快慢指針實(shí)現(xiàn),這里不贅述。因此在以下情況會(huì)有一個(gè)bug:
function Person(pname, sname){ this.name = pname || ""; this.spouse = sname || {}; } var p1 = new Person("Lily"); var p2 = new Person("Bob", p1); p1.spouse = p2; deepFreeze(p1); //會(huì)陷入無(wú)休止的遞歸。實(shí)際家庭成員關(guān)系更復(fù)雜,就更糟糕了。RangeError: Maximum call stack size exceeded(…)構(gòu)造函數(shù)(Constructor)
當(dāng)我們想創(chuàng)建很多個(gè)人的時(shí)候,就不會(huì)像上面這樣一個(gè)一個(gè)寫了。那我們就造一個(gè)工廠,用來(lái)生產(chǎn)人(感覺(jué)有點(diǎn)恐怖):
function CreatePerson(pname, page){ return { name: pname, age: page }; } p1 = CreatePerson("Lily", 21); p2 = CreatePerson("Bob", 12); console.log(p1); //Object {name: "Lily", age: 21} console.log(p2); //Object {name: "Bob", age: 12}
但是這樣寫并不符合傳統(tǒng)的編程思路。因此我們需要一個(gè)構(gòu)造函數(shù)(constructor, 也有書譯為構(gòu)造器)
關(guān)于構(gòu)造函數(shù)和普通函數(shù)的區(qū)別可以看javascript中this詳解中”構(gòu)造函數(shù)中的this"一節(jié)。
下面定義一個(gè)構(gòu)造函數(shù):
function Person(pname, page){ this.name = pname; this.age = page; this.work = function(){ console.log(this.name + " is working..."); }; } var p1 = new Person("Lily",23); var p2 = new Person("Lucy", 21); console.log(p1); p1.work(); console.log(p2); p2.work();
不過(guò)這樣寫這個(gè)函數(shù),每個(gè)對(duì)象都會(huì)包括一部分,太浪費(fèi)內(nèi)存。所以我們會(huì)把公共的部分放在prototype中:
function Person(pname, page){ this.name = pname; this.age = page; } Person.prototype.work = function(){ console.log(this.name + " is working..."); }; var p1 = new Person("Lily",23); var p2 = new Person("Lucy", 21); console.log(p1); p1.work(); console.log(p2); p2.work();
通過(guò)上面的輸出,我們看到,每個(gè)對(duì)象(p1,p2)都包含了一個(gè)__proto__屬性,這個(gè)是一個(gè)非標(biāo)準(zhǔn)屬性(ES6已經(jīng)把它標(biāo)準(zhǔn)化了),不過(guò)IE中沒(méi)有這個(gè)屬性。
原型鏈與繼承在學(xué)習(xí)原型鏈之前我們一定要區(qū)分清楚:prototype是構(gòu)造函數(shù)的屬性,而__proto__是對(duì)象的屬性。當(dāng)然我們依然用代碼說(shuō)話:
再來(lái)一段代碼:
function Person(pname, page){ this.name = pname; this.age = page; } Person.prototype.work = function(){ console.log(this.name + " is working..."); }; var p = new Person("Lily",23); console.log(p.constructor); //function Person(){...} console.log(p.__proto__); //Object console.log(Person.prototype); //Object console.log(Person.prototype.constructor); //function Person(){...} console.log(Person.__proto__); console.log(Person.constructor); console.log(Person.__proto__); //空函數(shù)function(){} console.log(Person.constructor); //function Function(){...}
說(shuō)到這里,就有必要學(xué)習(xí)一下原型鏈了。
js沒(méi)有類的概念,這樣就不會(huì)有繼承派生和多態(tài),但是實(shí)際編程中我們需要這樣的結(jié)構(gòu),于是js在發(fā)展過(guò)程中,就從一個(gè)沒(méi)有類的語(yǔ)言模擬出來(lái)類的效果,這里靠的就是prototype。
一個(gè)構(gòu)造函數(shù)的prototype永遠(yuǎn)指向他的父對(duì)象,這樣這個(gè)構(gòu)造函數(shù)new出來(lái)的對(duì)象就可以訪問(wèn)其父對(duì)象的成員,實(shí)現(xiàn)了繼承。
如果他的父對(duì)象的prototype又指向一個(gè)父對(duì)象的父對(duì)象,這樣一層層就構(gòu)成了原型鏈。如下(用瀏覽器內(nèi)置對(duì)象模型舉例):
console.log(HTMLDocument); console.log(HTMLDocument.prototype); //HTMLDocument對(duì)象 console.log(HTMLDocument.prototype.constructor.prototype); console.log(HTMLDocument.prototype.constructor.prototype.constructor.prototype); console.log(HTMLDocument.prototype.constructor.prototype.constructor.prototype.constructor.prototype); console.log(HTMLDocument.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype); /*......*/
如果你覺(jué)得這里應(yīng)該有一張圖,那就看看這個(gè)完整的對(duì)象關(guān)系圖(基于DOM),下文的相關(guān)例子也基于這個(gè)圖:
注意:原型鏈?zhǔn)怯懈F的,他總會(huì)指向Object,然后是null結(jié)束
那么__proto__是什么?一言以蔽之:對(duì)象的__proto__屬性指向該對(duì)象構(gòu)造函數(shù)的原型。如下:
function Person(pname, page){ this.name = pname; this.age = page; this.work = function(){ console.log(this.name + " is working..."); }; } var o = new Person("Lily",23); o.__proto__ === Person.prototype //true
上面圖中發(fā)現(xiàn),對(duì)象還有一個(gè)constructor屬性,這個(gè)屬性也很重要,新創(chuàng)建對(duì)象的constructor指向默認(rèn)對(duì)象的構(gòu)造函數(shù)本身,不過(guò)現(xiàn)實(shí)沒(méi)有這么簡(jiǎn)單。例如:
function Person(){ } var p1 = new Person(); console.log(p1.constructor); //function Person(){...} function Children(){ } Children.prototype = p1;//這一行和下一行聯(lián)立使用,不能忽略下一行 Children.prototype.constructor = Children; //修正constructor,這個(gè)不能省略 console.log(Person.prototype.constructor); //function Person(){...} console.log(p1.constructor); //function Child(){...}
當(dāng)我們建立了一個(gè)繼承關(guān)系后,會(huì)使新的構(gòu)造函數(shù)的prototype.constructor指向改構(gòu)造函數(shù)自己,像上面第9行一樣。從第11行也可以看出,系統(tǒng)本身也是這樣做的。這樣就構(gòu)成了下面這個(gè)圖的關(guān)系,此時(shí)父對(duì)象的constructor指向子構(gòu)造函數(shù):
注: 圖片來(lái)自網(wǎng)絡(luò)
從上面的這些例子我們不難發(fā)現(xiàn),函數(shù)也是一個(gè)對(duì)象。因此構(gòu)造函數(shù)也有了constructor和__proto__屬性。不過(guò)這里會(huì)比較簡(jiǎn)單:函數(shù)的constructor都是Function(){...};函數(shù)的__proto__都是個(gè)空函數(shù)
其實(shí)在js中除了基本類型(null, undefined, String, Number, Boolean, Symbol)以外,都是對(duì)象。可能你想反駁我:“js中一切都是對(duì)象”。我們看以下幾個(gè)例子:
//以數(shù)字類型為例 var a = 1; //基本類型 console.log(a); //1 console.log(typeof a); //number var b = new Number(1); //對(duì)象類型的數(shù)字 console.log(b); //Number {[[PrimitiveValue]]: 1} console.log(typeof b); //object
首先,js中基本類型中除了null和undefined以外的類型,都具有對(duì)象形式。但對(duì)象形式不等于基本類型。從上面的輸出結(jié)果來(lái)看,var a = 1;和var a = new Number(1);完全不是一回事。你或許會(huì)反駁我:"a有方法呀,基本類型怎么會(huì)有方法??!",我們?cè)倏聪乱粋€(gè)例子:
var a = 1; console.log(a.toFixed(2)); //1.00 var b = new Number(1); console.log(b + 2); //3
上面的例子看似基本類型a有了方法,對(duì)象又可以參與運(yùn)算。實(shí)際上這是隱式類型轉(zhuǎn)換的結(jié)果,上面第二行,瀏覽器自動(dòng)調(diào)用了new Number()把a(bǔ)轉(zhuǎn)換成了對(duì)象,而第四行利用ValueOf()方法把對(duì)象轉(zhuǎn)換成了數(shù)字。
既然函數(shù)也是個(gè)對(duì)象,那么我們不僅可以用構(gòu)造函數(shù)new一個(gè)對(duì)象出來(lái),也可以為它定義私有方法(變量)和靜態(tài)方法
function Person(pname){ var age = 10; //私有變量,外面訪問(wèn)不到 function getAge(){ //私有方法,外面訪問(wèn)不到 console.log(age); } this.name = pname; this.getInfo = function(){ //公有方法,也可以定義在prototype中 console.log(this.name); getAge.call(this); //注意這里的作用域和調(diào)用方式 }; }; Person.speak = function(){console.log("I am a person");}; //靜態(tài)方法 var p = new Person("Bob"); p.getInfo(); //Bob 10 Person.speak(); //"I am a person"
當(dāng)然實(shí)現(xiàn)簡(jiǎn)單的對(duì)象繼承不用這么復(fù)雜,可以使用Object.create(obj);返回一個(gè)繼承與obj的對(duì)象。對(duì)與Object.create()方法需要考慮一下幾種情況:
var o = {}; var r1 = Object.create(o); //創(chuàng)建一個(gè)r1繼承于o var r2 = Object.create(null); //創(chuàng)建一個(gè)r2繼承于null var r3 = Object.create(Object); //創(chuàng)建一個(gè)r3繼承于Object console.log(r1); //是一個(gè)繼承自o的對(duì)象 console.log(r2); //是一個(gè)空對(duì)象,沒(méi)有__proto__屬性 console.log(r3); //是一個(gè)函數(shù)
有了先前的知識(shí),我們可以寫出來(lái)一個(gè)函數(shù)實(shí)現(xiàn)Object.create()
function inherit(o){ //if(Object.create) return Object.create(o); if(o !== Object(o) && o !== null) throw TypeError("Object prototype may only be an Object or null"); function newObj(){}; newObj.prototype = o || {}; var result = new newObj(); if(o === null) result.__proto__ = null; return result; } var obj = {}; console.log(Object.create(obj)); console.log(inherit(obj)); console.log(Object.create(null)); console.log(inherit(null)); console.log(Object.create(Object)); console.log(inherit(Object));
看了這么多,怎么寫繼承比較合理,我們實(shí)現(xiàn)2個(gè)構(gòu)造函數(shù),讓Coder繼承Person。比較以下3種方法:
function Person(pname){ this.name = pname; } function Coder(){} //方法一:共享原型 Coder.prototype = Person.prototype; //方法二:實(shí)例繼承 Coder.prototype = new Person("Lily"); Coder.prototype.constructor = Coder; //方法三:本質(zhì)上還是實(shí)例繼承 Coder.prototype = Object.create(Person.prototype);
當(dāng)然還有其他的繼承方法:
//方法4:構(gòu)造繼承 function Person(pname){ this.name = pname; } function Coder(pname){ Person.apply(this, argument); } //方法5:復(fù)制繼承 function Person(pname){ this.name = pname; this.work = function() {...}; } var coder = deepCopy(new Person()); //拷貝 coder.code = function(){...}; //擴(kuò)展新方法 coder.language = "javascript"; //擴(kuò)展新屬性 coder.work = function() {...}; //重構(gòu)方法 //下面是深拷貝函數(shù) function deepCopy(obj){ var obj = obj || {}; var newObj = {}; deeply(obj, newObj); function deeply(oldOne, newOne){ for(var prop in oldOne){ if(!oldOne.hasOwnProperty(prop)) continue; if(typeof oldOne[prop] === "object" && oldOne[prop] !== null){ newOne[prop] = oldOne[prop].constructor === Array ? [] : {}; deeply(oldOne[prop], newOne[prop]); } else newOne[prop] = oldOne[prop]; } } return newObj; }
既然方法這么多,我們?cè)撊绾瓦x擇,一張表解釋其中的區(qū)別
--- | 共享原型 | 實(shí)例繼承 | 構(gòu)造繼承 | 復(fù)制繼承 |
---|---|---|---|---|
原型屬性 | 繼承 | 繼承 | 不繼承 | 繼承 |
本地成員 | 不繼承 | 繼承 | 繼承 | 繼承 |
子類影響父類 | Y | N | N | N |
執(zhí)行效率 | 高 | 高 | 高 | 低 |
多繼承 | N | N | Y | Y |
obj instanceof Parent | true | false | false | false |
子類的修改會(huì)影響父類是絕對(duì)不行的,所以共享原型是不能用的。在考慮到使用方便,只要不涉及多繼承就用實(shí)例繼承,多繼承中構(gòu)造繼承也好于復(fù)制繼承。
instanceofinstanceof用來(lái)判斷對(duì)象是否某個(gè)構(gòu)造函數(shù)的實(shí)例。這個(gè)東西很簡(jiǎn)單,不僅可以判斷是否直接構(gòu)造函數(shù)實(shí)例,還能判斷是否父對(duì)象構(gòu)造函數(shù)的實(shí)例
function Person(){} var p = new Person(); console.log(p instanceof Person); //true console.log(p instanceof Object); //true多態(tài)/重構(gòu)
js的方法名不能相同,我們只能模擬實(shí)現(xiàn)類似c++一樣的多態(tài)。
編譯時(shí)多態(tài)注意:這個(gè)名字只是用了強(qiáng)類型語(yǔ)言的說(shuō)法,js是個(gè)解釋型語(yǔ)言,沒(méi)用編譯過(guò)程。
在方法內(nèi)部判斷參數(shù)情況進(jìn)行重載
參數(shù)數(shù)量不同做不同的事情
//修改字體,僅用部分屬性舉例: function changeFont(obj, color, size, style){ if(arguments.lenght === 4){ //當(dāng)傳入了參數(shù)為4個(gè)參數(shù)時(shí)候做的事情 obj.style.fontSize = size; obj.style.fontColor = color; obj.style.fontStyle = style; return; } if(arguments.length === 2 && typeof arguments[1] === "object"){ //當(dāng)傳入了參數(shù)為2個(gè)參數(shù)時(shí)候做的事情 obj.style.fontSize = arguments[1].size || obj.style.fontSize; obj.style.fontStyle = arguments[1].style || obj.style.fontStyle; obj.style.fontColor = arguments[1].color || obj.style.fontColor; return; } throw TypeError("the font cannot be changed..."); }
參數(shù)類型不同做不同的事情
//構(gòu)造簡(jiǎn)單對(duì)象 function toObject(val){ if(val === Object(val)) return val; if(val == null) throw TypeError(""null" and "undefined" cannot be an Object..."); switch(typeof val){ case "number": return new Number(val); case "string": return new String(val); case "boolean": return new Boolean(val); case "symbol": return new Symbol(val); default: throw TypeError("Unknow type inputted..."); } }運(yùn)行時(shí)多態(tài)
java的多態(tài)都是編譯時(shí)多態(tài)。所以這個(gè)概念是源于c++的,c++利用虛基類實(shí)現(xiàn)運(yùn)行過(guò)程中同一段代碼調(diào)用不同的函數(shù)的效果。而在js中可以利用函數(shù)傳遞實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)
function demo(fun, obj){ obj = obj || window; fun.call(this); } function func(){ console.log("I"m coding in " + this.lang); } var lang = "C++"; var o = { lang: "JavaScript", func: function(){ console.log("I"m coding in " + this.lang); } }; demo(func); demo(o.func); demo(func, o);重寫
我們都知道子對(duì)象可以重寫父對(duì)象中的函數(shù),這樣子對(duì)象函數(shù)對(duì)在子對(duì)象中替代父對(duì)象的同名函數(shù)。但如果我們希望既在子對(duì)象中重寫父類函數(shù),有想使用父類同名函數(shù)怎么辦!分一下幾個(gè)情況討論:
//情況1 function Person(){ this.doing = function(){ console.log("I"m working..."); }; } function Coder(){ Person.call(this); var ParentDoing = this.doing; this.doing = function(){ console.log("My job is coding..."); ParentDoing(); } } var coder = new Coder(); coder.doing(); //測(cè)試 //情況2 function Person(){ } Person.prototype.doing = function(){ console.log("I"m working..."); }; function Coder(){ Person.call(this); this.doing = function(){ console.log("My job is coding..."); Person.prototype.doing.call(this); }; } var coder = new Coder(); coder.doing(); //測(cè)試 //情況3 function Person(){ } Person.prototype.doing = function(){ console.log("I"m working..."); }; function Coder(){ } Coder.prototype = Object.create(Person.prototype); Coder.prototype.constructor = Coder; Coder.super = Person.prototype; Coder.prototype.doing = function(){ console.log("My job is coding..."); Coder.super.doing(); }; var coder = new Coder(); coder.doing(); //測(cè)試
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97465.html
摘要:眾所周知,是一門面向?qū)ο蟮恼Z(yǔ)言,如果說(shuō)針對(duì)面向?qū)ο髞?lái)發(fā)問(wèn)的話,我會(huì)想到兩個(gè)問(wèn)題,在中,類與實(shí)例對(duì)象是如何創(chuàng)建的,類與實(shí)例對(duì)象又是如何實(shí)現(xiàn)繼承的。但是在中是指向的,因?yàn)槊恳粋€(gè)構(gòu)造函數(shù)其實(shí)都是這個(gè)對(duì)象構(gòu)造的,中子類的指向父類可以實(shí)現(xiàn)屬性的繼承。 眾所周知,Javascript是一門面向?qū)ο蟮恼Z(yǔ)言,如果說(shuō)針對(duì)面向?qū)ο髞?lái)發(fā)問(wèn)的話,我會(huì)想到兩個(gè)問(wèn)題,在js中,類與實(shí)例對(duì)象是如何創(chuàng)建的,類與實(shí)例對(duì)...
摘要:的類與繼承的類與一般的面向?qū)ο笳Z(yǔ)言有很大的不同,類的標(biāo)識(shí)是它的構(gòu)造函數(shù),下面先定義一個(gè)類顯然我們可以看出這兩個(gè)函數(shù)是不同的,雖然它們實(shí)現(xiàn)了相同的功能。利用構(gòu)造函數(shù)來(lái)繼承上面的方法子類顯然無(wú)法繼承父類的原型函數(shù),這樣不符合我們使用繼承的目的。 javascript的類與繼承 javascript的類與一般的面向?qū)ο笳Z(yǔ)言有很大的不同,類的標(biāo)識(shí)是它的構(gòu)造函數(shù),下面先定義一個(gè)類 var ...
摘要:從原型對(duì)象指向構(gòu)造函數(shù)畫一條帶箭頭的線。線上標(biāo)注,表示該原型對(duì)象的構(gòu)造函數(shù)等于。但除此之外,若構(gòu)造函數(shù)所指的顯示原型對(duì)象存在于的原型鏈上,結(jié)果也都會(huì)為。執(zhí)行構(gòu)造函數(shù),并將指針綁定到新創(chuàng)建的對(duì)象上。 做前端開(kāi)發(fā)有段時(shí)間了,遇到過(guò)很多坎,若是要排出個(gè)先后順序,那么JavaScript的原型與對(duì)象絕對(duì)逃不出TOP3。 如果說(shuō)前端是海,JavaScript就是海里的水 一直以來(lái)都想寫篇文章梳理...
摘要:類的方法相當(dāng)于之前我們定義在構(gòu)造函數(shù)的原型上。的構(gòu)造函數(shù)中調(diào)用其目的就是調(diào)用父類的構(gòu)造函數(shù)。是先創(chuàng)建子類的實(shí)例,然后在子類實(shí)例的基礎(chǔ)上創(chuàng)建父類的屬性。 前言 首先歡迎大家關(guān)注我的Github博客,也算是對(duì)我的一點(diǎn)鼓勵(lì),畢竟寫東西沒(méi)法獲得變現(xiàn),能堅(jiān)持下去也是靠的是自己的熱情和大家的鼓勵(lì)。 許久已經(jīng)沒(méi)有寫東西了,因?yàn)殡s七雜八的原因最近一直沒(méi)有抽出時(shí)間來(lái)把寫作堅(jiān)持下來(lái),感覺(jué)和跑步一...
摘要:二正文中與的區(qū)別接口只聲明成員方法,不做實(shí)現(xiàn)。在中,我們可以采用全新的基于類繼承的模式設(shè)計(jì)更優(yōu)雅的語(yǔ)義化接口,這是因?yàn)橹械目梢岳^承動(dòng)態(tài)構(gòu)造的類,這一點(diǎn)和其他的靜態(tài)聲明類的編程語(yǔ)言不同。 一 前言 1.在typescript上遇到過(guò)實(shí)例化對(duì)象的兩種寫法:implement和extends。extends很明顯就是ES6里面的類繼承,那么implement又是做什么的呢?它和extends...
閱讀 716·2021-11-18 10:02
閱讀 3609·2021-09-02 10:21
閱讀 1753·2021-08-27 16:16
閱讀 2066·2019-08-30 15:56
閱讀 2394·2019-08-29 16:53
閱讀 1382·2019-08-29 11:18
閱讀 2961·2019-08-26 10:33
閱讀 2649·2019-08-23 18:34