天天看點

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

可能不少學習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();