摘要:中的和是一門(mén)很靈活的語(yǔ)言,尤其是。即然是面向?qū)ο蟮木幊陶Z(yǔ)言,那也是不可或缺的。在中,永遠(yuǎn)指向的是他的調(diào)用者。定義是存在于實(shí)例化后對(duì)象的一個(gè)屬性,并且指向原對(duì)象的屬性。我們?cè)跀U(kuò)展的時(shí)候,同時(shí)父類也會(huì)有對(duì)應(yīng)的方法,這很顯然是一個(gè)很嚴(yán)重的問(wèn)題。
javascript中的this和new
javascript是一門(mén)很靈活的語(yǔ)言,尤其是function。他即可以以面向過(guò)程的方式來(lái)用,比如:
function getName() { return "張三" } getName()
也可以以面向?qū)ο蟮姆绞絹?lái)用,比如:
function User() { this.name = "張三" } var user = new User()
javascript是如何實(shí)現(xiàn)面向?qū)ο缶幊痰哪兀克峁┝?b>new這個(gè)關(guān)健字,有了new就可以把對(duì)象進(jìn)行實(shí)例化,比如:
function User(name, age){ this.name = name this.age = age } var zs = new User("zs", 20) var ls = new User("ls", 30)
new出來(lái)的兩個(gè)實(shí)例,會(huì)開(kāi)辟兩塊新的內(nèi)存區(qū)域,來(lái)保存這些數(shù)據(jù),同時(shí)有指針指向?qū)ο?b>User。所以就有instanceof這個(gè)運(yùn)算符,這個(gè)運(yùn)算符的意思就是:a是不是A的實(shí)例。比如上例:zs instanceof User的返回值是true。
即然是面向?qū)ο蟮木幊陶Z(yǔ)言,那this也是不可或缺的。在javascript中,this永遠(yuǎn)指向的是他的調(diào)用者。要理解這句話,我們舉幾個(gè)例子:
例子1
function test(){ this.name = "zs" } test()
當(dāng)執(zhí)行完成之后,這個(gè)name會(huì)直接掛載到window下面,因?yàn)槭沁@樣執(zhí)行的:winow.test()。
例子2
var game = document.getElementById("game") game.addEventListener("click", function () { setTimeout(function () { this.innerText = "Clicked" }, 1000) })
這個(gè)例子很簡(jiǎn)單,點(diǎn)擊某個(gè)元素的時(shí)候,1秒后,讓他里面的html改成Clicked,可是你發(fā)現(xiàn)這樣不好使,就是因?yàn)?b>this指向的問(wèn)題,因?yàn)檫@里面的this也指向window了,所以你執(zhí)行window.innerText會(huì)返回Clicked。
例子3
function User(name) { this.name = name this.getName = function () { console.log(this.name) } } var u = new User("zs") u.getName()
這里面的this的指向沒(méi)有問(wèn)題,因?yàn)榘凑罩暗脑瓌t,調(diào)用者是u,也就是User的實(shí)例,所以在方法getName中,this.name相當(dāng)于u.name,所以打印出zs。
prototype和__proto__prototype
javascript是面向?qū)ο蟮恼Z(yǔ)言,這個(gè)上面已經(jīng)提過(guò)了,其他面向?qū)ο笳Z(yǔ)言有一個(gè)必備我就是繼承,很顯然在ES6之前,沒(méi)有extends這個(gè)關(guān)鍵字,那么,javascript就是利用prototype的原型鏈來(lái)實(shí)現(xiàn)繼承。先記住這句話,我們一會(huì)會(huì)說(shuō)到繼承。prototype其實(shí)只是對(duì)象的一個(gè)屬性,在Chrome控制臺(tái)下,可以直接看出來(lái),但是這個(gè)屬性很特殊,這個(gè)屬性下可以掛載任何的對(duì)象、方法、屬性,而且掛載的東西可以反映到實(shí)例下對(duì)象上。說(shuō)的比較繞,我們看個(gè)例子:
function User(name) { this.name = name } User.prototype.getName = function () { console.log(this.name) } var u = new User("zs") u.getName()
我們?cè)?b>User.prototype上面掛載了getName的方法,在下面實(shí)例化User之后的u,就可以訪問(wèn)這個(gè)方法。
看到這,你可以有個(gè)疑問(wèn),既然是給實(shí)例化對(duì)象用的,那下面這種方式豈不是更好、更直觀?
function User(name) { this.name = name this.getName = function () { console.log(this.name) } } var u = new User("zs") u.getName()
如果我們和Java語(yǔ)言進(jìn)行對(duì)應(yīng),User相當(dāng)是Class,name相當(dāng)于屬性,getName相當(dāng)于里面的方法,完美映射!可以這樣有一個(gè)問(wèn)題啊,就是太費(fèi)內(nèi)存了。因?yàn)槊?b>new一個(gè)對(duì)象,都會(huì)占用一塊內(nèi)存區(qū)域,這樣User里面方法屬性越多,那么每個(gè)實(shí)例化的對(duì)象都會(huì)對(duì)這些進(jìn)行 深復(fù)制,那么占用的內(nèi)存空間就越大。那么javascript是如何通過(guò)prototype來(lái)解決內(nèi)存占用的問(wèn)題的呢?這就需要引用__proto__。
__proto__
定義:__proto__是存在于實(shí)例化后對(duì)象的一個(gè)屬性,并且指向原對(duì)象的prototype屬性。
比如上例中的u.__proto__ === User.prototype返回的是true。可以在Chrome控制臺(tái)下查看u.__proto__。
你會(huì)發(fā)現(xiàn),不對(duì)吧,User對(duì)象下也有__proto__啊。那是因?yàn)?b>User也是Function的實(shí)例,不信你可以試一下User.__proto__ === Function.prototype的返回值。其實(shí)我們這樣定義函數(shù):function test(){}是一個(gè)語(yǔ)法糖的寫(xiě)法,全拼應(yīng)該是這樣:var test = new Function("alert(1)")。
現(xiàn)在我們來(lái)解釋為什么使用prototype能節(jié)省內(nèi)存。不知道你有沒(méi)有注意到上面一句代碼u.__proto__ === User.prototype,我為什么要使用三等?因?yàn)槿忍?hào)除了值、類型外,內(nèi)存地址也必須是相等的,也就是說(shuō)User不管實(shí)例化多少對(duì)象,他們的prototype只有一份,放在User里。客戶端的瀏覽器環(huán)境不像服務(wù)器,內(nèi)存還是比較緊張的,所以javascript通過(guò)這種方式,來(lái)解決內(nèi)存占用問(wèn)題。
繼承方式一:直接繼承
先舉個(gè)例子:
var Animal = function (name) { this.name = name } Animal.prototype.walk = function () { console.log("I can walk!") } Animal.prototype.getName = function () { console.log("My name is " + this.name + "!") } var Dog = function (name) { this.name = name } Dog.prototype = Animal.prototype var d = new Dog("Tom") d.getName() d.walk()
我們建立一個(gè)父類Animal對(duì)象,建立一個(gè)子類Dog,我們想讓Dog也有walk方法和getName方法,通過(guò)上面對(duì)prototype的了解,我們最先想到的是Dog.prototype = Animal.prototype,這樣子類和父類的prototype相等,那子類就有父類所有方法嘍,繼承鏈條是這樣的:d.__proto__ === Dog.prototype === Animal.prototype。
這樣很直觀,但是也有一個(gè)比較嚴(yán)重的問(wèn)題。我們?cè)跀U(kuò)展Dog的時(shí)候,同時(shí)父類也會(huì)有對(duì)應(yīng)的方法,這很顯然是一個(gè)很嚴(yán)重的問(wèn)題。
方式二:實(shí)例化繼承
為了解決上面的問(wèn)題,我們需要引入一個(gè)空函數(shù),這個(gè)空函數(shù)做為橋梁,把子類和父類之間的連接切斷。實(shí)現(xiàn)如下:
var F = function () {} F.prototype = Animal.prototype Dog.prototype = new F() Dog.prototype.say = function () { console.log("Say") }
為什么是Dog.prototype = new F()呢?因?yàn)檫@樣即可以繼承Animal的所有方法,他的原型鏈?zhǔn)沁@樣的:
d.__proto__ --> Dog.prototype --> new F().__proto__
執(zhí)行walk方法,F(xiàn)已經(jīng)有了,所以就不會(huì)再找Animal了
新增加的方法又不影響父類,這句怎么講?因?qū)嵗膶?duì)象沒(méi)有prototype屬性!所以不會(huì)影響
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/84429.html
摘要:不必在構(gòu)造函數(shù)中定義對(duì)象實(shí)例的信息。其次,按照一切事物皆對(duì)象的這餓極本的面向?qū)ο蟮姆▌t來(lái)說(shuō),類本身并不是一個(gè)對(duì)象,然而原型方式的構(gòu)造函數(shù)和原型本身也是個(gè)對(duì)象。第二個(gè)問(wèn)題就是在創(chuàng)建子類型的實(shí)例時(shí),不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)。 前言 對(duì)象(Object)應(yīng)該算是js中最為重要的部分,也是js中非常難懂晦澀的一部分。更是面試以及框架設(shè)計(jì)中各出沒(méi)。寫(xiě)這篇文章,主要參考與JavaScrip...
摘要:引言對(duì)于面向?qū)ο螅嘈糯蠹乙欢ú荒吧?chuàng)建對(duì)象面向?qū)ο蟮谝徊绞鞘裁创饎?chuàng)建對(duì)象。構(gòu)造函數(shù)優(yōu)于工廠模式也是在于它可以通過(guò)辨識(shí)出一類的對(duì)象。 引言 對(duì)于面向?qū)ο螅嘈糯蠹乙欢ú荒吧W罱戳艘恍╆P(guān)于es6面向?qū)ο蟮闹R(shí),正好通過(guò)這篇文章把關(guān)于面向?qū)ο蟮臇|西給串起來(lái)分享給大家。 什么是對(duì)象 很多人會(huì)鄙視我,說(shuō)你這篇文章是騙騙剛?cè)胄械男∨笥训陌桑裁词菍?duì)象我還能不知道?罵我的吃瓜群眾先冷靜一下,...
摘要:會(huì)造成內(nèi)存浪費(fèi)的問(wèn)題構(gòu)造函數(shù)繼承聲明父類聲明子類生成實(shí)例組合式繼承組合式繼承是汲取了兩者的優(yōu)點(diǎn),既避免了內(nèi)存浪費(fèi),又使得每個(gè)實(shí)例化的子類互不影響。 寫(xiě)在前面 既然是淺談,就不會(huì)從原理上深度分析,只是幫助我們更好地理解... 面向?qū)ο笈c面向過(guò)程 面向?qū)ο蠛兔嫦蜻^(guò)程是兩種不同的編程思想,剛開(kāi)始接觸編程的時(shí)候,我們大都是從面向過(guò)程起步的,畢竟像我一樣,大家接觸的第一門(mén)計(jì)算機(jī)語(yǔ)言大概率都是C語(yǔ)...
摘要:面向?qū)ο竺嫦驅(qū)ο缶幊痰娜Q是,簡(jiǎn)稱,面向?qū)ο缶幊淌怯贸橄蠓绞絼?chuàng)建基于現(xiàn)實(shí)世界模型的一種編程模式。面向?qū)ο缶幊痰娜齻€(gè)主要特征是封裝繼承多態(tài)。 面向?qū)ο?面向?qū)ο缶幊痰娜Q是Object Oriented Programming,簡(jiǎn)稱OOP,面向?qū)ο缶幊淌怯贸橄蠓绞絼?chuàng)建基于現(xiàn)實(shí)世界模型的一種編程模式。面向?qū)ο缶幊炭梢钥醋鍪鞘褂靡幌盗袑?duì)象相互協(xié)作的軟件設(shè)計(jì),面向?qū)ο蟪绦蛟O(shè)計(jì)的目的是在編程中促...
摘要:如果沒(méi)有學(xué)習(xí)過(guò)計(jì)算機(jī)科學(xué)的程序員,當(dāng)我們?cè)谔幚硪恍﹩?wèn)題時(shí),比較熟悉的數(shù)據(jù)結(jié)構(gòu)就是數(shù)組,數(shù)組無(wú)疑是一個(gè)很好的選擇。 showImg(https://segmentfault.com/img/bVTSjt?w=400&h=300); 1、常見(jiàn) CSS 布局方式詳見(jiàn): 一些常見(jiàn)的 CSS 布局方式梳理,涉及 Flex 布局、Grid 布局、圣杯布局、雙飛翼布局等。http://cherryb...
閱讀 2242·2021-11-17 09:33
閱讀 2783·2021-11-12 10:36
閱讀 3406·2021-09-27 13:47
閱讀 894·2021-09-22 15:10
閱讀 3494·2021-09-09 11:51
閱讀 1399·2021-08-25 09:38
閱讀 2762·2019-08-30 15:55
閱讀 2613·2019-08-30 15:53