摘要:中的和是一門很靈活的語言,尤其是。即然是面向對象的編程語言,那也是不可或缺的。在中,永遠指向的是他的調用者。定義是存在于實例化后對象的一個屬性,并且指向原對象的屬性。我們在擴展的時候,同時父類也會有對應的方法,這很顯然是一個很嚴重的問題。
javascript中的this和new
javascript是一門很靈活的語言,尤其是function。他即可以以面向過程的方式來用,比如:
function getName() { return "張三" } getName()
也可以以面向對象的方式來用,比如:
function User() { this.name = "張三" } var user = new User()
javascript是如何實現面向對象編程的呢?他提供了new這個關健字,有了new就可以把對象進行實例化,比如:
function User(name, age){ this.name = name this.age = age } var zs = new User("zs", 20) var ls = new User("ls", 30)
new出來的兩個實例,會開辟兩塊新的內存區域,來保存這些數據,同時有指針指向對象User。所以就有instanceof這個運算符,這個運算符的意思就是:a是不是A的實例。比如上例:zs instanceof User的返回值是true。
即然是面向對象的編程語言,那this也是不可或缺的。在javascript中,this永遠指向的是他的調用者。要理解這句話,我們舉幾個例子:
例子1
function test(){ this.name = "zs" } test()
當執行完成之后,這個name會直接掛載到window下面,因為是這樣執行的:winow.test()。
例子2
var game = document.getElementById("game") game.addEventListener("click", function () { setTimeout(function () { this.innerText = "Clicked" }, 1000) })
這個例子很簡單,點擊某個元素的時候,1秒后,讓他里面的html改成Clicked,可是你發現這樣不好使,就是因為this指向的問題,因為這里面的this也指向window了,所以你執行window.innerText會返回Clicked。
例子3
function User(name) { this.name = name this.getName = function () { console.log(this.name) } } var u = new User("zs") u.getName()
這里面的this的指向沒有問題,因為按照之前的原則,調用者是u,也就是User的實例,所以在方法getName中,this.name相當于u.name,所以打印出zs。
prototype和__proto__prototype
javascript是面向對象的語言,這個上面已經提過了,其他面向對象語言有一個必備我就是繼承,很顯然在ES6之前,沒有extends這個關鍵字,那么,javascript就是利用prototype的原型鏈來實現繼承。先記住這句話,我們一會會說到繼承。prototype其實只是對象的一個屬性,在Chrome控制臺下,可以直接看出來,但是這個屬性很特殊,這個屬性下可以掛載任何的對象、方法、屬性,而且掛載的東西可以反映到實例下對象上。說的比較繞,我們看個例子:
function User(name) { this.name = name } User.prototype.getName = function () { console.log(this.name) } var u = new User("zs") u.getName()
我們在User.prototype上面掛載了getName的方法,在下面實例化User之后的u,就可以訪問這個方法。
看到這,你可以有個疑問,既然是給實例化對象用的,那下面這種方式豈不是更好、更直觀?
function User(name) { this.name = name this.getName = function () { console.log(this.name) } } var u = new User("zs") u.getName()
如果我們和Java語言進行對應,User相當是Class,name相當于屬性,getName相當于里面的方法,完美映射!可以這樣有一個問題啊,就是太費內存了。因為每new一個對象,都會占用一塊內存區域,這樣User里面方法屬性越多,那么每個實例化的對象都會對這些進行 深復制,那么占用的內存空間就越大。那么javascript是如何通過prototype來解決內存占用的問題的呢?這就需要引用__proto__。
__proto__
定義:__proto__是存在于實例化后對象的一個屬性,并且指向原對象的prototype屬性。
比如上例中的u.__proto__ === User.prototype返回的是true。可以在Chrome控制臺下查看u.__proto__。
你會發現,不對吧,User對象下也有__proto__啊。那是因為User也是Function的實例,不信你可以試一下User.__proto__ === Function.prototype的返回值。其實我們這樣定義函數:function test(){}是一個語法糖的寫法,全拼應該是這樣:var test = new Function("alert(1)")。
現在我們來解釋為什么使用prototype能節省內存。不知道你有沒有注意到上面一句代碼u.__proto__ === User.prototype,我為什么要使用三等?因為三等號除了值、類型外,內存地址也必須是相等的,也就是說User不管實例化多少對象,他們的prototype只有一份,放在User里。客戶端的瀏覽器環境不像服務器,內存還是比較緊張的,所以javascript通過這種方式,來解決內存占用問題。
繼承方式一:直接繼承
先舉個例子:
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()
我們建立一個父類Animal對象,建立一個子類Dog,我們想讓Dog也有walk方法和getName方法,通過上面對prototype的了解,我們最先想到的是Dog.prototype = Animal.prototype,這樣子類和父類的prototype相等,那子類就有父類所有方法嘍,繼承鏈條是這樣的:d.__proto__ === Dog.prototype === Animal.prototype。
這樣很直觀,但是也有一個比較嚴重的問題。我們在擴展Dog的時候,同時父類也會有對應的方法,這很顯然是一個很嚴重的問題。
方式二:實例化繼承
為了解決上面的問題,我們需要引入一個空函數,這個空函數做為橋梁,把子類和父類之間的連接切斷。實現如下:
var F = function () {} F.prototype = Animal.prototype Dog.prototype = new F() Dog.prototype.say = function () { console.log("Say") }
為什么是Dog.prototype = new F()呢?因為這樣即可以繼承Animal的所有方法,他的原型鏈是這樣的:
d.__proto__ --> Dog.prototype --> new F().__proto__
執行walk方法,F已經有了,所以就不會再找Animal了
新增加的方法又不影響父類,這句怎么講?因實例化的對象沒有prototype屬性!所以不會影響
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/84429.html
摘要:不必在構造函數中定義對象實例的信息。其次,按照一切事物皆對象的這餓極本的面向對象的法則來說,類本身并不是一個對象,然而原型方式的構造函數和原型本身也是個對象。第二個問題就是在創建子類型的實例時,不能向超類型的構造函數中傳遞參數。 前言 對象(Object)應該算是js中最為重要的部分,也是js中非常難懂晦澀的一部分。更是面試以及框架設計中各出沒。寫這篇文章,主要參考與JavaScrip...
摘要:引言對于面向對象,相信大家一定不陌生。創建對象面向對象第一步是什么答創建對象。構造函數優于工廠模式也是在于它可以通過辨識出一類的對象。 引言 對于面向對象,相信大家一定不陌生。最近看了一些關于es6面向對象的知識,正好通過這篇文章把關于面向對象的東西給串起來分享給大家。 什么是對象 很多人會鄙視我,說你這篇文章是騙騙剛入行的小朋友的吧,什么是對象我還能不知道?罵我的吃瓜群眾先冷靜一下,...
摘要:會造成內存浪費的問題構造函數繼承聲明父類聲明子類生成實例組合式繼承組合式繼承是汲取了兩者的優點,既避免了內存浪費,又使得每個實例化的子類互不影響。 寫在前面 既然是淺談,就不會從原理上深度分析,只是幫助我們更好地理解... 面向對象與面向過程 面向對象和面向過程是兩種不同的編程思想,剛開始接觸編程的時候,我們大都是從面向過程起步的,畢竟像我一樣,大家接觸的第一門計算機語言大概率都是C語...
摘要:面向對象面向對象編程的全稱是,簡稱,面向對象編程是用抽象方式創建基于現實世界模型的一種編程模式。面向對象編程的三個主要特征是封裝繼承多態。 面向對象 面向對象編程的全稱是Object Oriented Programming,簡稱OOP,面向對象編程是用抽象方式創建基于現實世界模型的一種編程模式。面向對象編程可以看做是使用一系列對象相互協作的軟件設計,面向對象程序設計的目的是在編程中促...
摘要:如果沒有學習過計算機科學的程序員,當我們在處理一些問題時,比較熟悉的數據結構就是數組,數組無疑是一個很好的選擇。 showImg(https://segmentfault.com/img/bVTSjt?w=400&h=300); 1、常見 CSS 布局方式詳見: 一些常見的 CSS 布局方式梳理,涉及 Flex 布局、Grid 布局、圣杯布局、雙飛翼布局等。http://cherryb...
閱讀 2234·2021-11-17 09:33
閱讀 2774·2021-11-12 10:36
閱讀 3395·2021-09-27 13:47
閱讀 884·2021-09-22 15:10
閱讀 3485·2021-09-09 11:51
閱讀 1392·2021-08-25 09:38
閱讀 2757·2019-08-30 15:55
閱讀 2608·2019-08-30 15:53