可能不少學習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 {
100;
function o2(arg){
o1.apply(this, arg);
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();
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 n +arguments.callee(n - 1)
五、bind
var first_object = {
num: 42
};
second_object = {
num: 24
function multiply(mult) {
return
this.num * mult; //全局作用域下定義的 this指向window
//把函數對象綁定到指定對象,作為該對象的方法,并傳回該對象的方法
Function.prototype.bind = function(obj)
var method = this,
temp = function() {
method.apply(obj, arguments);
return temp;
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、一個閉包就是當一個函數傳回時,一個沒有釋放資源的棧區。
~~~ 一個閉包就是當一個函數傳回時,一個沒有釋放資源的棧區
<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>
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)
七、原型鍊
ECMAScript 為 Object 類型定義了一個内部 [[prototype]]
屬性。這個屬性不能通過腳本直接通路,但在屬性通路器解析過程中,則需要用到這個内部[[prototype]] 屬性所引用的對象鍊--即原型鍊。可以通過一個公共的
prototype 屬性,來對與内部的 [[prototype]] 屬性對應的原型對象進行指派或定義。
相關技巧:
應用call和apply還有一個技巧在裡面,就是用call和apply應用另一個函數(類)以後,目前的
函數(類)就具備了另一個函數(類)的方法或者是屬性,這也可以稱之為“繼承”。看下面示例:
// 繼承的示範
function base() {
this.member = " dnnsun_Member";
this.method = function() {
window.alert(this.member);
extend() {
base.call(this);
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();