javascript
浅谈JavaScript中的对象和类型(上)
?
?
JavaScript是一種不同于任何強類型程序設計語言的腳本語言,這決定了它對于許多強類型語言的程序員來說有很多莫名其妙、難以理解的地方,本文是本人對JavaScript的一些實踐總結出來的簡單易懂的結論(至少對我來說是這樣)。我一直篤信任何語言的設計者都不至于腦子短路設計出連他自己都記不清楚的規則,所以很顯然,JavaScript很多特性,例如this,看起來無比復雜,事實上不過是沒有抽象理解的原因。本文就試圖從一個抽象的角度來還原這些復雜規則背后的抽象之美。
一、自定義對象
盡管JavaScript的確是存在一些基元類型(例如數值、字符串、數組等),但我更傾向于在我們的“自定義類型”對象中,是沒有類型這個說法的(事實上JavsScript的typeof運算符得到的結果只有固定的幾個)。或者說傳統的強類型程序設計語言中的類型,在JavaScript中是找不到的。因為JavaScript中的所有自定義對象都是橡皮泥,你可以任意增刪改成員。
自定義對象一般用new關鍵字創建,但實際上函數本身也是一個對象,也是一個自定義對象,所以我先隨便創建一個對象:
var a = function() { }; //你可以將這一行改為var a = new Object();,或者new任何東西,都不影響結果。那么接下來我們就可以為這個對象增加成員:
a.test = "hello world!"; window.alert(a.test);同樣的,也可以修改這個成員,例如我們把它變成一個函數:
a.test = function() { window.alert("hello world!"); }; a.test();?
所以我們知道,構造一個對象,事實上完全沒有必要去用new 函數名()這樣的高級語法,如果你只是需要一個很簡單的對象,下面的語法就可以了:
function constructor() {var person = new Object();person.name = "Ivony";person.sexual = "男";//...return person; }var manager = constructor();window.alert(manager.name); window.alert(manager.sexual);二、全局scope(作用域)。
我們剛剛在定義a這個變量的時候,使用了一個JavaScript的關鍵字:var。在解釋這個關鍵字之前,我們先考慮下面的代碼:
function test() {a = 100;window.alert(window.a); }test();?
猜猜結果是什么?
這是許多傳統程序員無法理解的地方,明明是對變量a賦值,怎么window.a也賦值了。這就是JavaScript有意思的全局scope現象。
簡單的說JavaScript中沒有傳統程序設計語言中分配于堆棧上的變量的概念,取而代之的是scope對象(很多時候這不是一個真正的對象)。你直接用a = 100這樣的代碼賦值的時候,你并不是給一個叫做a的變量賦值,而是給scope對象的一個名為a的成員賦值。
如果不使用var關鍵字,默認的scope對象就是全局scope也就是window,所以a = 100就等同于window.a = 100。
當然,你也可以想到,alert等同于window.alert,那么window.alert也應等同于window.window.alert。事實的確如此,window對象真的有個成員叫做window,而且就是它自身,所以你window后面點多少個window都是一樣的。
那么,var關鍵字的用途就是,將變量附著于函數的作用域(或者說當前的作用域)對象上,而非全局作用域對象。考慮下面的代碼:
function a(arg) {window.alert(arg); }function test() {var a = function(arg) { window.alert("alert: " + arg); };a("hello world"); }test(); a("hello world"); ?這個執行結果應該就不難猜了。
?
值得注意的是,使用var關鍵字聲明變量,與聲明的位置毫無關系(只要是在函數的花括弧內)!這意味著你將腳本改成這個樣子,結果不會有任何變化:
function test() {a = function(arg) { window.alert("alert: " + arg); };a("hello world");if (false){var a = 0;} }?
JavaScript只關心,你是否在這個作用域中,使用var修飾了這個變量名。
最后需要說明的問題是,函數的作用域對象并不等同于函數對象!換言之var a = 100并不能使得函數對象多出一個成員a其值為100。函數的作用域對象是函數被調用時存在的對象,這與函數對象(用于調用函數的對象)不是一回事。函數的作用域對象是一個運行時自動創建自動回收的對象,你甚至無法捕獲到這個對象。
三、this對象
this對象恐怕是JavaScript里面最難于理解的對象了,有人還總結出了N種情況下this分別代表什么含義。但事實上如果我們了解JavaScript的實際執行原理,就不難搞清楚this到底是什么。this一般等同于調用函數的上下文中,函數的宿主對象。
先看一個最常見的情況:
function test() {this.alert("abc"); }test();從執行結果來看,test函數中的this應該是window對象,因為調用了window.alert方法。
那為什么在這段腳本中this是window呢?原因就是在調用上下文中test其實是window的一個成員。因為上面的腳本從某種意義上來說等同于:
window.test = function() {this.alert("abc"); }window.test();很顯然調用test的時候,window就是test的宿主對象。
?
理解了這一點,我們來看下面這段腳本:
function alarm() {this.a = window.alert;test(); }function test() {this.a("abc"); }alarm();a("hello world!");怎么理解這一段代碼?首先調用alarm函數,這個函數里面的this是什么?沒錯,是window。為什么?因為alarm調用的時候其實等同于window.alarm,所以函數內的this就是window。然后this.a = window.alert,這等同于window.a = window.alert。然后執行test函數,同理,test函數里面的this也是window。整理后,其實整個代碼可以解釋成這樣:
function alarm() {window.a = window.alert;test(); }function test() {window.a("abc"); }window.alarm();window.a("hello world!"); ?來看一個this不是window的情況:
var o = new Object(); //與var o = function() { };一樣,都可以創建一個自定義對象,我們只需要一個對象,不必關心它是函數還是什么。o.text = "hello object!"; //設置o的text成員o.alarm = function()//定義一個函數,并設置為o的成員 {window.alert(this.text); //注意這個this }alarm = o.alarm; text = "hello world!";alarm(); o.alarm();猜一下執行結果吧。
值得注意的是,其實兩個alarm是同一個函數,不同的是在調用上下文中,一個的宿主是window,一個的宿主是o,所以調用的結果不同。this所代表的對象,與函數本身沒有任何關系,它取決于調用函數的上下文!
最后一個值得特別說明的東西是,函數的scope對象是不能用this捕獲到的,考慮如下腳本:
text = "hello world!";function test() {var text = "hello function!";var a = function(){window.alert(this.text);}a(); }test();結果將是hello world!而不是hello function!,當然你可能會想,a的宿主應該是執行函數時的函數的scope對象,然后這個對象應該有個成員text。但事實并非如此,在這種情況下,a的宿主仍然是window。這一點可以理解為:函數的scope對象并不是一個真正的對象,它只是JavaScript運行時用來保存變量的東西。
這個現象,現在并沒有特別好的辦法去解釋,當然,大家只需要記住,如果調用函數的時候,前面沒有".",那么this就總會是window了。
轉載于:https://www.cnblogs.com/Ivony/archive/2010/01/29/1659354.html
總結
以上是生活随笔為你收集整理的浅谈JavaScript中的对象和类型(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: qq飞车骑士精神多少出 PC版官方网站
- 下一篇: 抖音极速版app怎么升级