在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>
複製代碼