摘要:原型之所以被稱為原型,可能正是因為這種不可重載的特質。而一旦實例化,那么將指向實例化的對象。首先是,我使用了,直接利用貓咪的年齡進行計算得出體重返回給屬性。
和java比起來,javascript真的是松散的無以復加,不過這也讓我們在無聊之余,有精力去探討一些復雜的應用,從而在開發之路上,獲得一些新的想法。
javascript中的類的構造javascript中有對象的概念,卻沒有類的概念。對于基礎不牢的同學,很難在類和對象之間加以區分,這里簡單的將它們的關系概況為:類是一種抽象的概念,例如瓶子、人、笨蛋;而對象,則是指這種概念中的實體,比如“那個美女手中的那只瓶子”“村長是一個地道的農民”“她的男朋友是個笨蛋”;實例化,就是指以類為基礎構建一個實體。類所擁有的特征,其實例化對象,也一定擁有這些特征,而且實例化后可能擁有更多特征。
javascript在用到對象時,完全沒有類的概念,但是編程的世界里,無奇不有,我們卻可以通過function構造出一種假想的類,從而實現javascript中類的構造。
比如,我們通過下面的方法來構造一個類:
//java class Book { private String name; private double price; public Book(name,price) {this.name=name;this.price=price;} public void setName(String name) { this.name = name;} public void setPrice(double price) {this.price = price;} public String getInfo() {...} } Book book1 = new Book("java",13.3); //javascript function Book(name,price) { this.name = name; this.price = price; this.setName = function(name) {this.name = name;}; this.setPrice = function(price) {this.price = price}; this.getInfo = function() {return this.name + " " + this.price;}; } var book1 = new Book("java",13.3);
這是很好玩兒的一種嘗試。這也是本文要討論的所有問題的起源。
function(){}()讓變量快速初始化結果在《javascript立即執行某個函數:插件中function(){}()再思考》一文中,我詳細闡述了function(){}()的作用及理解思路。這里不再贅述,現在,我們面臨的新問題是,知道了它的作用,我們如何使用它?
讓我們來看一段代碼:
var timestamp = function(){ var timestamp = Date.parse(new Date()); return timestamp/1000; }();
當我們要使用一個變量時,我們希望這個變量在一個環節完成我們的賦值,使用上面的這種方法,可以減少代碼上下文執行邏輯,如果按照我們以前的方法,代碼可能會寫成:
var timestamp = Date.parse(new Data()); timestamp = timestamp/1000;
看上去好像比上面的操作簡潔多了,只需要兩行代碼。但是我們仔細去觀察,就會發現第一段代碼其實本身僅是一個賦值操作,在function中完成的所有動作將會在function執行完后全部釋放,整個代碼看上去好像只執行了一條語句一樣。
而實際上更重要的意義在于它可以讓一個變量在初始化時,就具備了運算結果的效果。
使用new function初始化一個可操作對象第一部分講到了javascript中的類,而使用new function就可以實例化這個類。但是我們實際上有的時候在為一個變量賦值的時候,希望直接將它初始化為一個可操作的對象,比如像這樣:
// 這里的數據庫操作是我虛擬出來的一種數據庫操作形式 var $db = new function(){ var $db = db_connect("127.0.0.1","root",""); $db.use("database"); this.select = function(table,where) { var result = $db.query("select from " + table + " where " + where); return $db.fetchAll(result); } };
而當我們要對數據庫database進行查詢時,只需要通過var list = $db.select("table","1=1");進行操作即可,數據庫的初始化結果已經在$db這個變量中了。
Function是由function關鍵字定義的函數對象的原型在javascript中,多出了一個原型的概念。所謂原型,其實就是一個對象的本質,但復雜就復雜在,原型本身也是對象,因此,任何一個對象又可以作為其他對象的原型。Function就相當于一個系統原型,可以把它理解為一種“基本對象類型”,是“對象”這個概念范疇類的基本數據類型。除了Function之外,其實還有很多類似的首字母大寫的對象原型,例如Object, Array, Image等等。有一種說法是:javascript中所有的一切都是對象(除了基本數據類型,其他的一切全是對象),所有的對象都是Object衍生出來的。(按照這種說法,我們應該返回去再思考,上面說的類的假設是否成立。)
極其重要的prototype概念prototype的概念在javascript中極其重要,它是javascript中完成上面說的“一切皆對象”的關鍵。有了prototype,才有了原型,有了原型,才有了javascript五彩繽紛的世界(當然,也有人說是雜亂的)。我們可以這樣去理解prototype:世界上本沒有javascript,上帝說要有Object,于是有了Object,可是要有Function怎么辦?只需要對Object進行擴展,可是如何擴展?只需要用prototype……當然,這是亂扯的,不過在javascript中,只要是function,就一定會有一個prototype屬性。實際上確實是這樣
Function.prototype.show = function() {...}
在原型的基礎上通過prototype新增屬性或方法,則以該對象為原型的實例化對象中,必然存在新增的屬性或方法,而且它的內容是靜態不可重載的。原型之所以被稱為原型,可能正是因為這種不可重載的特質。
比如上面的這段代碼,會導致每一個實例化的function,都會具備一個show方法。而如果我們自己創建了一個類,則可以通過prototype將之轉化為原型:
function Cat() {...} Cat.prototype.run = function() {}; var cat1 = new Cat();
這時,對于cat1而言,Cat就是原型,而該原型擁有一個run的原始方法,所以無論實例化多少個Cat,每一個實例化對象都有run方法,而且該方法是不能被重載的,通過cat1.run = function(){}是無效的。
為了和其他語言的類的定義方法統一,我們可以將這種原型屬性在定義類的時候,寫在類的構造里面:
function Cat() { .... Cat.prototype.run = function() {}; }new Function()是函數原型的一個實例化
在理解了Function原型的概念之后,再來看new Function()就顯得很容易了。首先來看下我們是怎么使用這種奇特的寫法的:
var message = new Function("msg","alert(msg)"); // 等價于: function message(msg) { alert(msg); }
new Function(參數1,參數2,...,參數n,函數體),它的本意其實是通過實例化一個Function原型,得到一個數據類型為function的對象,也就是一個函數,而該變量就是函數名。
this在這類function中的指向this在javascript中真的是無法讓我們捉摸透徹。但是有一個小竅門,就是:一般情況下,this指向的是當前實例化對象,如果沒有找到該對象,則是指向window。從使用上來講,我們應該排除new Function的討論,因為它和我們常用的函數聲明是一致的。
普通的函數中this的指向
函數聲明的時候,如果使用了this,那么就要看是把該函數當做一個對象加以返回,還是以僅執行函數體。普通函數執行時,我們完全沒有引入對象、類這些概念,因此,this指向window。通過代碼來看下:
var msg; function message(msg) { this.msg = msg; } message("ok"); alert(msg);
首先是聲明一個函數message,在函數中this.msg實際上就是window.msg,也實際上就是代碼開頭的msg。因此,當執行完message("ok")的時候,開頭的全局變量msg也被賦值為ok。
通過function構造類時this的指向
如果function被構造為一個類,那么必然存在該類被實例化的一個過程,如果沒有實例化,那么該類實際上并沒有在程序中被使用。而一旦實例化,那么this將指向實例化的對象。
var age = 3; var cat1 = new function() { this.name = "Tom"; this.age = 2; this.weight = function(age) { var age = age * 2; var _age = this.age * 2; return "weight by age:" + age + "; weight by this.age:" + _age; }(this.age); this.eye = new function() { this.size = "1.5cm"; this.color = "red"; }; this.catching = function(mouse) { return this.name + " is catching " + mouse; }; }; alert(cat1.weight); alert(cat1.eye.color); alert(cat1.catching("Jerry"));
上面代碼中標記了4處紅色的this的使用。根據我們的原則,this指向實例化對象,我們來對每一個this進行分解。
首先是cat1.weight,我使用了function(){}(),直接利用貓咪的年齡進行計算得出體重返回給weight屬性。
第一個this.age出現在function(){}(this.age),這個this.age實際上是一個傳值過程,如果你對我之前分析function(){}()比較了解的話,應該知道,this.age實際上是和前面this.age = 2指同一個,這里的this.age的this,首先要去找它所在的function,然后看這個function是否被實例化,最后確認,確實被實例化為cat1,因此this=cat1。
第二個this.age出現在function(){this.age}()。同樣,你先需要對function(){}()再次深入了解,實際上,function(){}()就是執行一個函數而已,我們前面提到了,普通函數執行中this=window,所以,這里的this.age實際上是var age = 3。
第三個this.color出現在new function(){this.color},這里就比較好玩,由于有一個new,實際上也被實例化了,只不過是對匿名類的實例化,沒有類名,而且實例化僅可能出現這一次。因此,this.color的this要去找new function的主人,也就是this.eye,而this.eye的this=cat1,所以cat1.eye.color="red"。
第四個this.name出現在function(){this.name},它出現在cacthing方法中,它既不是普通的函數執行,也不是實例化為對象,而是正常的類中的方法的聲明,因此this指向要去找它所在的function被實例化的對象,也就是cat1。
小結本文雖然講了很多,但核心點實際上還是落在javascript的面向對象這個點上。javascript中雖然沒有明確的class的概念,那是因為它首先基于type這樣的基礎概念,并強調一切皆對象的這種思想。如果從哲學上講,javascript真正符合道生一,一生二,二生萬物的原則。不過本文沒有提到和繼承相關的內容,所有解釋也是我自己的一種理解方式,不代表真正的原理,讀者請自己通過其他途徑進行學習。
本文發布在我的個人博客,請到原地址交流:http://www.tangshuang.net/2280.html
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78950.html
摘要:這幾天因為對于中的作用域鏈和原型鏈有點混淆,當訪問一個不帶有修飾的變量時,我想知道它的搜索順序,因為作用域鏈的鏈結點也是一個變量對象,那么當在這個變量對象中查找變量時會不會沿著它的原型鏈查找呢這樣就有兩種可能先查找作用域鏈前端的變量對象,然 這幾天因為對于JavaScript中的作用域鏈和原型鏈有點混淆,當訪問一個不帶有this修飾的變量時,我想知道它的搜索順序,因為作用域鏈的鏈結點也...
摘要:上面的例子應用了匿名函數這個特性,還可以使用構造函數或者閉包來添加事件監聽器另一個重要特性,則是上面這段代碼中最后一行的最后一個參數,用來控制監聽器對于冒泡事件的響應。在這里你不能使用閉包或者匿名函數,并且控制域也是有限的。 原文出處:addEventListener vs onclick 之所以會想到這個話題,是因為在回顧自己之前寫的為 button 動態綁定事件的函數時,腦海里忽...
摘要:事件的響應分區為三個階段捕獲目標冒泡階段。綁定的多個事件會被覆蓋,后者覆蓋前者。再用轉換成數值表示。如實際數量為,則展示為項目中使用過濾器做的處理可以抽取方法的,調整相關,可以獲取指定位數的縮寫。 CSS html5中a的download屬性 定義和用法download 屬性定義下載鏈接的地址或指定下載文件的名稱。文件名稱沒有限定值,瀏覽器會自動在文件名稱末尾添加該下載文件的后綴 (...
摘要:使用實現計算器,開啟你的計算之旅吧效果圖代碼如下,復制即可使用主體顯示框微軟雅黑功能區?使用html+css+js實現計算器,開啟你的計算之旅吧 ? 效果圖: ?? ?代碼如下,復制即可使用: ? ?? /* 主體 */ .counter{ width: 396px; ...
閱讀 3170·2021-09-10 10:51
閱讀 3351·2021-08-31 09:38
閱讀 1639·2019-08-30 15:54
閱讀 3129·2019-08-29 17:22
閱讀 3214·2019-08-26 13:53
閱讀 1960·2019-08-26 11:59
閱讀 3283·2019-08-26 11:37
閱讀 3308·2019-08-26 10:47