關於js的一些關鍵知識點(call,apply,callee, caller,clourse,prototypeChain)

來源:互聯網
上載者:User

標籤:des   class   java   ext   使用   string   

 

可能不少學習javascript在使用call,apply,callee時會感到困惑,以下希望對於你有所協助:

1、~~~call ,apply是函數(函數對象)的方法;callee是函數arguments對象的屬性 引用函數自身

2、~~~call,apply改變內容物件this的指向

3、~~call apply方法讓函數作為另一個對象的方法被調用

4、~~ apply方法只能接受數組作為參數

>> call

f.call(o,1,2) 等同於
o.m = f;
o.m(1,2);
例1:
function o1(value){
if(value < 100){
this.value = value;
}else{
this.value = 100;
}
}

function o2(value){
o1.call(this,value); //改變o1函數中,內容物件this的指向
alert(this.value);
}

var o = new o2(133554) //100 改變了this的指向

例2:
function c1(){
this.m1 = function(){
alert(this.name);
}
}

function c2(){
this.name = “mike”;
}
var nc1 = new c1();
var nc2 = new c2(); //必須
nc1.m1.call(nc2); //mike 把方法m1作為對象nc2的方法來引用

>> apply
例3:
function o1(arg){
if (arguments[1] < 100) {
this.value = arguments[1] ;
}
else {
this.value = 100;
}
}

function o2(arg){
o1.apply(this, arg);
alert(this.value);
}

var o = new o2([101,60]) //60 參數只能是數組

>> callee

callee用法,常用於匿名函數中
var factorial = function(x){
if(x <= 1){
return 1;
}
return x * arguments.callee(x - 1); //回呼函數自身
}
alert(factorial(5)); //120


---------------------------------------------------------------------------------


二、apply方法
apply方法的第一個參數也是要傳入給當前對象的對象,即函數內部的this。後面的參數都是傳遞給當前對象的參數。
對於apply和call兩者在作用上是相同的,但兩者在參數上有區別的。對於第一個參數意義都一樣,但對第二個參數:apply傳入的是一個參數數組,也就是將多個參數組合成為一個數組傳入,而call將函數參數順序傳入即可(從第二個參數開始)。
如 func.call(func1,var1,var2,var3) 對應的apply寫法為:func.apply(func1,[var1,var2,var3])

~~~~使用apply最大的好處,可以將當前函數的arguments對象(arguments是偽數組)作為apply的第二個參數傳入。

var func=new function(){this.a="func"}
var myfunc=function(x,y){
var a="myfunc";
alert(this.a);
alert(x + y);
}

//call 與 apply調用時傳入參數的差別

myfunc.call(func,"var"," fun");// "func" "var fun"
myfunc.apply(func,["var"," fun"]);// "func" "var fun"


三、caller 屬性

返回一個對函數的引用,即調用了當前函數的函數體。
functionName.caller :functionName 對象是所執行函數的名稱。
說明:
對於函數來說,caller 屬性只有在函數執行時才有定義。 如果函數是由 JScript 程式的頂層調用的,那麼 caller 包含的就是 null 。如果在字串上下文中使用 caller 屬性,那麼結果和 functionName.toString 一樣,也就是說,顯示的是函數的反編譯文本。

function CallLevel(){
if (CallLevel.caller == null)
alert("CallLevel was called from the top level.");
else
alert("CallLevel was called by another function:\n"+CallLevel.caller);
}

function funCaller(){
CallLevel();
}

CallLevel();

funCaller();


四、callee屬性
返回正被執行的 Function 對象
[function.]arguments.callee:可選項 function 參數是當前正在執行的 Function 對象的名稱。
說明:
callee 屬性的初始值就是正被執行的 Function 對象。
callee 屬性是 arguments 對象的一個成員,它表示對函數對象本身的引用,這有利於匿函數的遞迴或者保證函數的封裝性,例如下邊樣本的遞迴計算1到n的自然數之和。而該屬性僅當相關函數正在執行時才可用。還有需要注意的是callee擁有length屬性,這個屬性有時用於驗證還是比較好的。arguments.length是實參長度,arguments.callee.length是形參長度,由此可以判斷調用時形參長度是否和實參長度一致。

//callee可以列印其本身
function calleeDemo() {
alert(arguments.callee);
}
calleeDemo();


//用於驗證參數
function calleeLengthDemo(arg1, arg2) {
if (arguments.length==arguments.callee.length) {
window.alert("驗證形參和實參長度正確!");
return;
} else {
alert("實參長度:" +arguments.length +" ,形參長度: " +arguments.callee.length);
}
}

//遞迴計算
var sum = function(n){
if (n <= 0)
return 1;
else
return n +arguments.callee(n - 1)
}


五、bind

var first_object = {
num: 42
};
var second_object = {
num: 24
};
function multiply(mult) {
return this.num * mult; //全域範圍下定義的 this指向window
}
//把函數對象綁定到指定對象,作為該對象的方法,並返回該對象的方法
Function.prototype.bind = function(obj) {
var method = this,
temp = function() {
return method.apply(obj, arguments);
};
return temp;
}
var first_multiply = multiply.bind(first_object); //綁定內容物件 並返回封裝原函數的匿名函數
first_multiply(5); // returns 42 * 5
var second_multiply = multiply.bind(second_object);
second_multiply(5); // returns 24 * 5


六、JS閉包(Closure)
所謂“閉包”,指的是一個擁有許多變數和綁定了這些變數的環境的運算式(通常是一個函數),因而這些變數也是該運算式的一部分。

~~~~ good explaintion
關於閉包,最簡單的描述就是 ECMAScript 允許使用內建函式--即函數定義和函數運算式位於另一個函數的函數體內。而且,這些內建函式可以訪問它們所在的外部函數中聲明的所有局部變數、參數和聲明的其他內建函式。當其中一個這樣的內建函式在包含它們的外部函數之外被調用時,就會形成閉包。也就是說,內建函式會在外部函數返回後被執行。而當這個內建函式執行時,它仍然必需訪問其外部函數的局部變數、參數以及其他內建函式。這些局部變數、參數和函式宣告(最初時)的值是外部函數返回時的值,但也會受到內建函式的影響。

簡而言之,閉包的作用就是在父函數執行完並返回後,閉包使得Javascript的記憶體回收機制GC不會收回父函數所佔用的資源,因為父函數的內建函式的執行需要依賴它裡面的變數。

閉包的兩個特點:

1、作為一個函數變數的一個引用 - 當函數返回時,其處於啟用狀態。
2、一個閉包就是當一個函數返回時,一個沒有釋放資源的棧區。

~~~ 一個閉包就是當一個函數返回時,一個沒有釋放資源的棧區

例1:

<script type="text/javascript">
function setupSomeGlobals() {
// Local variable that ends up within closure
var num = 666;

// Store some references to functions as global variables
gAlertNumber = function() { alert(num); }
gIncreaseNumber = function() { num++; }
gSetNumber = function(x) { num = x; }
}
</script>
<button onclick="setupSomeGlobals()">產生 - setupSomeGlobals()</button>
<button onclick="gAlertNumber()">輸出值 - gAlertNumber()</button>
<button onclick="gIncreaseNumber()">增加 - gIncreaseNumber()</button>
<button onclick="gSetNumber(5)">賦值5 - gSetNumber(5)</button>


例2:

<script type="text/javascript">
function newClosure(someNum, someRef) {
// Local variables that end up within closure
var num = someNum;
var anArray = [1,2,3];
var ref = someRef;
return function(x) {
num += x;
anArray.push(num);
alert(‘num: ‘ + num + ‘ nanArray ‘ + anArray.toString() + ‘ nref.someVar ‘ + ref.someVar);
}
}
var closure1 = newClosure(40, {someVar:‘ never-online‘})
var closure2 = newClosure(99, {someVar:‘ BlueDestiny‘})
closure1(4)
closure2(3)
</script>


七、原型鏈
ECMAScript 為 Object 類型定義了一個內部 [[prototype]] 屬性。這個屬性不能通過指令碼直接存取,但在屬性訪問器解析過程中,則需要用到這個內部[[prototype]] 屬性所引用的對象鏈--即原型鏈。可以通過一個公用的 prototype 屬性,來對與內部的 [[prototype]] 屬性對應的原型對象進行賦值或定義。


相關技巧:

應用call和apply還有一個技巧在裡面,就是用call和apply應用另一個函數(類)以後,當前的
函數(類)就具備了另一個函數(類)的方法或者是屬性,這也可以稱之為“繼承”。看下面樣本:

// 繼承的示範
function base() {
this.member = " dnnsun_Member";
this.method = function() {
window.alert(this.member);
}
}
function extend() {
base.call(this);
window.alert(this.member);
window.alert(this.method);
}

上面的例子可以看出,通過call之後,extend可以繼承到base的方法和屬性。

順便提一下,在javascript架構prototype裡就使用apply來建立一個定義類的模式,

其實現代碼如下:

var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
解析:從代碼看,該對象僅包含一個方法:Create,其返回一個函數,即類。但這也同時是類的
建構函式,其中調用initialize,而這個方法是在類建立時定義的初始化函數。通過如此途徑,
就可以實現prototype中的類建立模式

樣本:
var vehicle=Class.create();
vehicle.prototype={
initialize:function(type){
this.type=type;
}
showSelf:function(){
alert("this vehicle is "+ this.type);
}
}

var moto=new vehicle("Moto");
moto.showSelf();

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.