js方法和原型繼承(一)

在js語言規範中並不存在方法這一律念,方便起見,將做爲對象屬性的函數成爲方法javascript

this引用的規則java

a.在最外層代碼中,this引用的是全局對象app

b.在函數內,this引用根據函數調用方式不一樣而不一樣函數

函數內部的this引用 見下表this


函數的調用方式prototype


this引用的引用對象對象


構造函數調用繼承


所生成的對象ip


方法調用原型鏈


接收方對象


apply或call調用


由apply或call的參數指定的對象


其它方式調用


全局對象


接收方對象是這樣一種對象

經過點運算符或者中括號運算符調用對象方法時,在運算符左側所指定的對象

下面是一個關於方法和接收方對象的具體實例


複製代碼

<script>

var obj={

    x:3,

    doit:function(){

        p("method is called:  "+this.x);

    }

};

obj.doit();//對象obj是接收方對象 doit是方法

obj['doit']();//對象obj是接收方對象 doit是方法

//結果同樣 method is called: 3

</script>

複製代碼

this引用應注意的點

this的引用的引用對象會隨着方法的調用方式不一樣而不一樣


複製代碼

<script>

var obj={

    x:3,

    doit:function(){

        p("method is called:  "+this.x);

    }

};

var fn=obj.doit;//將obj.doit引用的Function對象賦值給全局變量

fn();//method is called: undefined  函數內的this引用引用了全局變量

var x=5;

fn();//method is called: 5

var obj2={x:4,doit2:fn};//將obj的方法(Function對象的引用)賦值給了另外一個對象obj2的屬性

obj2.doit2();//method is called: 4   方法內的this引用引用了對象obj2

</script>

<script>

var obj={

    x:3,

    doit:function(){

        p("doit is called "+this.x);this.doit2();

    },

    doit2:function(){

        p("doit2 is called "+this.x);

    }

};

obj.doit();

//doit is called 3

//doit2 is called 3  

//若是將doit2前面的this去掉,則會查找全局裏的doit2 嵌套的函數將按照做用域順序由內到外的順序查找

</script>

複製代碼

apply與call

在Function對象中包含apply和call這兩種方法,經過他們調用的函數的this引用能夠指向任意的特定對象,也就是他們能夠

顯式指定接收方對象


複製代碼

<script>

function f(a){

    p(this.x+":"+a);

}

var obj={x:4};

f.apply(obj,[2]);  //4  經過apply調用f函數內部this指向了obj

f.call(obj,2);  //4     經過call調用f函數內部this指向了obj

var obj={

    x:3,

    doit:function(){

        p("method is called:"+this.x);

    }

};

var obj2={x:4};

obj.doit.apply(obj2);//method is called:4

p(Math.max(4,5,1,2));

var arr=[1,3,2,0,99];

var mx=Math.max.apply(null,arr);//沒提供第一個參數 則global對象將被用做ths.obj

p(mx);//99

</script>

複製代碼

原型繼承

形式上的理解

類名.prototype.方法名=function(參數){方法體}


複製代碼

<script>

function Myclass(x,y){

    this.x=x;

    this.y=y;

    this.say=function(){

        p(this.x+":"+this.y);

    }

}

Myclass.prototype.show=function(){

    p(this.x,this.y);

}

var obj1=new Myclass(1,2);

obj1.show();

p('show' in obj1);//true

p(obj1.hasOwnProperty('show')) //false

p(obj1.hasOwnProperty('say'));  //true

p('show' in Myclass);//false

p("say" in Myclass);//false

p(typeof Myclass);//function

</script>

複製代碼

原型鏈

原型繼承支持一種稱爲原型鏈的功能,使用原型鏈有2個前提

a.全部的函數(對象)都具備名爲prototype的屬性(prototype屬性所引用的對象則稱爲prototype對象) 

【對象實例 如上代碼中的obj1沒有prototype屬性】


複製代碼

<script>

p( 'prototype' in obj1);//false

p('__proto__' in obj1);//true

p('prototype' in Myclass);//true

p("__proto__" in Myclass);//true

 </script>

複製代碼

b.全部的對象都含有一個(隱藏的)連接,用以指向在對象生成過程當中所使用的構造函數(Function對象)的prototype對象b.全部的對象都含有一個(隱藏的)連接,用以指向在對象生成過程當中所使用的構造函數(Function對象)的prototype對象


複製代碼

<script>

p(obj1.__proto__===Myclass.prototype);//true

p(Myclass.__proto__);// function Empty() {}

p(obj1.prototype);//undefined

p('x' in Myclass);//false


</script>

複製代碼

對象(類的實例)對屬性的讀取 查找順序

1.對象自身的屬性(經過實例化類獲取的屬性)

2.隱式連接所引用的對象(即構造函數的prototype對象)的屬性 (obj1.__proto__=Myclass.prototype)

3.第二項中的對象的隱式連接所引用的對象的屬性

4.反覆按照第三步的規則查找直至所有查找完畢(查找的終點是Object.prototype對象)


當一個函數對象被建立時,Function構造器產生的函數對象會運行相似這樣的一些代碼

this.prototype={constructor:this}

新函數的對象被賦予一個prototype屬性,他的值是包含constructor屬性且屬性值爲該新函數的對象,這個prototype對象是存放繼承特徵的地方,

由於javascript語言沒有提供一種方法去肯定哪一個函數是打算用來作構造器的,因此每一個函數都會獲得一個prototype對象

constructor沒什麼用

當採用構造器調用模式,即用new去調用一個函數,函數執行方式將發生改變

若是new 運算符是一個方法而不是一個運算符,它可能會這樣執行


複製代碼

<script>

function a(){   }

p(a.prototype); //[object Object]

p(a.prototype.constructor);    //function a(){ }

p(a.prototype.__proto__==Function.prototype);//false

p(a.prototype.__proto__==Object.prototype);//true


p('method' in Function);//false

//僞代碼

Function.method('new',function(){

    //建立一個新對象,它繼承自構造器函數的原型對象

    var that=Object.create(this.prototype);

    //調用構造器函數,綁定 this到新對象上

    var other=this.apply(that,arguments);

    //若是它的 返回值不是一個對象,就返回該新對象

    return (typeof other==='object' && other)||that;

});

</script>

複製代碼

相關文章
相關標籤/搜索