JavaScript之原型、函數、實例


JavaScript 函數語法

函數就是包裹在花括號中的代碼塊,前面使用了關鍵詞 function:

function functionname()
{
     // 執行代碼
}

當調用該函數時,會執行函數內的代碼。

可以在某事件發生時直接調用函數(比如當用戶點擊按鈕時),並且可由 JavaScript 在任何位置進行調用。

lamp JavaScript 對大小寫敏感。關鍵詞 function 必須是小寫的,並且必須以與函數名稱相同的大小寫來調用函數

在調用函數時,您可以向其傳遞值,這些值被稱為參數。

這些參數可以在函數中使用。

您可以發送任意多的參數,由逗號 (,) 分隔:

myFunction( argument1,argument2)

當您聲明函數時,請把參數作為變量來聲明:

function myFunction( var1, var2)
{
代碼
}

變量和參數必須以一致的順序出現。第一個變量就是第一個被傳遞的參數的給定的值,以此類推。

在進行函數調用的時候,不管實參的數目大於形參還是小於形參,被調用的函數都會執行;在JS中函數不介意傳遞進來多少個參數,也不在乎傳進來的參數是什么數據類型。發生函數調用的時候可以給一個實參也可以給多個實參,之所以會這樣,是因為在js中的參數在內部是用一個數組來表示。函數接收到的始終是這個數組,而不關心數組中包含哪些參數,如果這個數組不包含任何參數也無所謂,包含多個參數也沒問題,在函數體內可以通過arguments(參數)對象來訪問這個參數數組,從而獲取傳遞給參數的每個參數。 arguments對象和數組對象相類似,可以通過下標來獲取傳入的每一個元素(第一個元素是arguments[0]);也可以使用length屬性來確定傳遞進來多少個參數,arguments對象的長度是由傳入的參數個數決定,不是由定義函數的參數的個數決定

四種調用函數的方式及this指向

1、函數調用模式,this指向的全局對象window.

實例1:

函數聲明

1
2
3
4
5
function add(a,b) {
     return a+b;
}
 
console.log(add(1,2));

實例2:

函數表達式

1
2
3
4
5
var add= function (a,b) {
     return a+b;
}
 
console.log(add(1,2));

2、方法調用模式,this指向當前的對象

var o = {
     prop: 21,
     f: function () {
         return this .prop;
     }
};
console.log(o.f());

3、構造器模式,this指向新創建的實例對象,也就是這里的o

function MyClass() {
     this .a = 21;
}
var o = new MyClass();
console.log(o.a); //21

4、apply\call模式,這兩個的第一參數即this,當第一個參數為null,this指向window;當第一個參數為一個對象,this就指向當前這個對象。

call和apply的作用一樣,只是接受參數的方式不一樣,call接受的是多個單個參數,apply接受的是參數數組。
call和apply的作用簡單地可以說成,當一個對象實例缺少一個函數/方法時,可以調用其他對象的現成函數/方法,其方式是通過替換其中的this為這個對象實例,改變函數運行時的上下文。call方法的妙用:1、繼承 2、改變函數運行時的this指針
例如:

function Dog(){ this.sound="汪汪汪"; } Dog.prototype.bark=function(){ alert(this.sound); }

現在我有另外一個cat對象:

var cat={sound:'喵喵喵'}

我也想讓這個cat對象可以調用bark方法,這時候就不用重新為它定義bark方法了,可以用call/apply調用Dog類的bark方法:

Dog.prototype.bark.call(cat);

或者:

dog.bark.call(cat);

加點東西,變成一個帶參數的栗子:

function Dog(){ this.sound="汪汪汪"; } Dog.prototype.bark=function(words){ alert(this.sound+" "+words); } var dog=new Dog(); dog.bark("有小偷");//alert:汪汪汪 有小偷 Dog.prototype.bark.call(cat,"餓了");//alert:喵喵喵 餓了

普通函數與構造函數的區別

普通函數與構造函數相比有四個明顯特點:

1.不需要用new關鍵字調用

    fn();

2.可以用return語句返回值

    function fn(a,b){ return a+b; } alert(fn(2,3));//alert:5

3.函數內部不建議使用this關鍵字
我們說不建議使用,當然硬要用是可以的,只是要注意這時候發生了什么。如果在普通函數內部使用this關鍵字定義變量或函數,因為這時候this指向的是window全局對象,這樣無意間就會為window添加了一些全局變量或函數。

    function greeting(){ this.name="sheila"; alert("hello "+this.name); } greeting();//alert:hello sheila alert(window.name);//alert:sheila

4.函數命名以駝峰方式,首字母小寫

普通函數相比,構造函數有以下明顯特點:

1.用new關鍵字調用

    var prince=new Prince("charming",25);

2.函數內部可以使用this關鍵字
在構造函數內部,this指向的是構造出的新對象。用this定義的變量或函數/方法,就是實例變量或實例函數/方法。需要用實例才能訪問到,不能用類型名訪問。

    prince.age;//25 Prince.age;//undefined

3.默認不用return返回值
構造函數是不需要用return顯式返回值的,默認會返回this,也就是新的實例對象。當然,也可以用return語句,返回值會根據return值的類型而有所不同。

構造函數里調用return時,分兩種情況:

3.1 return的是五種簡單數據類型:String,Number,Boolean,Null,Undefined。
這種情況下,忽視return值,依然返回this對象。

3.2 return的是Object
這種情況下,不再返回this對象,而是返回return語句的返回值。

    function Person(name){ this.name=name; return {name:"cherry"} } var person=new Person("sheila"); person.name;//cherry person;//Object {name: "cherry"}

4.函數命名建議首字母大寫,與普通函數區分開。
不是命名規范中的,但是建議這么寫。

使用new關鍵字實例化的時候發生了什么?

以上文中的Prince()函數舉個栗子:

1.第一步,創建一個空對象。

var prince={}

2.第二步,將構造函數Prince()中的this指向新創建的對象prince。
3.第三步,將prince的_proto_屬性指向Prince函數的prototype,創建對象和原型間關系
4.第四步,執行構造函數Prince()內的代碼

原型對象

 function Person(name){
    this.name = name;
}

(google瀏覽器)

如上,當我們創建一個函數,系統就會為這個函數自動分配一個prototype指針,指向它的原型對象。並且可以發現,這個原型對象包含兩個部分(constructor 和 __proto__)其中constructor指向函數自身。(這里形成了一個小閉環)

var p = new Person("jack");
console.log(p);

 

我們將該函數作為模版創建實例(new方法)的時候,我們發現創建出的實例是一個與構造函數同名的object,這個object是獨立的,也就是這里的p,他只包含了一個__proto__指針(實例沒有prototype,強行訪問則會輸出undefined),這個指針指向上面提到的構造函數的prototype原型對象,則可以得出:p.__proto__===Person.prototype

結果如下:

 在查看下Object的原型對象:

通過上面的代碼可以看到:

  • Object對象本身是一個函數對象。
  • 既然是Object函數,就肯定會有prototype屬性,所以可以看到"Object.prototype"的值就是"Object {}"這個原型對象。
  • 反過來,當訪問"Object.prototype"對象的"constructor"這個屬性的時候,就得到了Obejct函數。
  • 另外,當通過"Object.prototype.__proto__"獲取Object原型的原型的時候,將會得到"null",也就是說"Object {}"原型對象就是原型鏈的終點了

在查看下Function的對象:

結果分析 :

  • 在JavaScript中有個Function對象(類似Object),這個對象本身是個函數;所有的函數(包括Function,Object)的原型(__proto__)都是"Function.prototype"。
  • Function對象作為一個函數,就會有prototype屬性,該屬性將對應"function () {}"對象。
  • Function對象作為一個對象,就有"__proto__"屬性,該屬性對應"Function.prototype",也就是說,"Function.__proto__ === Function.prototype"
  • 對於Function的原型對象"Function.prototype",該原型對象的"__proto__"屬性將對應"Object {}"

在這里對"prototype"和"__proto__"進行簡單的介紹:

  • 對於所有的對象,都有__proto__屬性,這個屬性對應該對象的原型
  • 對於函數對象,除了__proto__屬性之外,還有prototype屬性,當一個函數被用作構造函數來創建實例時,該函數的prototype屬性值將被作為原型賦值給所有對象實例(也就是設置實例的__proto__屬性)。也就是Person.prototype===p.__proto__

1、每個函數都有prototype屬性,這個屬性指向函數的原型對象

2、所有對象的__proto__都指向其構造器(constructor)的prototype

舉個栗子:

function Person(name){

  this.name = name;

}

var p = new Person("jack");

console.log(p.__proto__===Person.prototype);//true

console.log(p.__proto__===p.constructor.prototype);//true

3、構造函數、實例和原型對象的區別與聯系

3.1 實例就是通過構造函數創建的。實例創造出來就具有constructor屬性(指向構造函數)和__proto__屬性(指向原型對象)

3.2 構造函數中有一個prototype屬性。這個屬性是一個指針,指向它的原型對象

3.3 原型對象內部也有一個指針(constructor)指向構造函數。Person.prototype.constructor=Person;

3.4 Person.prototype.__proto__語句獲取原型對象的原型,將得到Object對象。所有對象的原型都將追溯到Object對象。

Person.prototype.__proto__ === Object.prototype; //true

 

最后上一個圖,便於理解

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM