首頁 >web前端 >js教程 >JS中call/apply、arguments、undefined/null方法詳解

JS中call/apply、arguments、undefined/null方法詳解

高洛峰
高洛峰原創
2017-01-04 17:17:031398瀏覽

a.call和apply方法詳解
----------------------------------------- ---------------------------------------

call方法: 

  語法:call ([thisObj[,arg1[, arg2[, [,.argN]]]]]) 

  定義:呼叫一個物件的一個方法,以另一個物件取代目前物件。 

  說明: call 方法可以用來取代另一個物件呼叫一個方法。 call 方法可將一個函數的物件上下文從初始的上下文變更為由 thisObj 指定的新物件。如果沒有提供 thisObj 參數,那麼 Global 物件被用作 thisObj。 

apply方法: 

  語法:apply([thisObj[,argArray]]) 

  定義:應用某一物件的一個方法,用另一個物件取代目前物件的一個方法。

  說明:如果 argArray 不是一個有效的數組或不是 arguments 對象,那麼將導致一個 TypeError。如果沒有提供 argArray 和 thisObj 任何一個參數,那麼 Global 物件將被用作 thisObj, 並且無法被傳遞任何參數。

實例學習:

function add(a,b){ alert(a+b);}
function sub(a,b){ alert(a-b);}
add.call(sub,3,1);

   

  列印結果為4。呼叫add函數,但呼叫物件(上下文環境)不是add對象,而是sub函數物件。注意:js中的函數其實是對象,函數名稱是對 Function 物件的參考。

function Animal(){
this.name = "Animal";
this.showName = function(){ alert(this.name);}
}
function Cat(){ this.name = "Cat"; }
var animal = new Animal();
var cat = new Cat();
animal.showName.call(cat,",");//输出结果为"Cat"
animal.showName.apply(cat,[]);//输出结果为"Cat"

   

  call 的意思是把animal 的方法放到cat上執行,上下文環境為cat,原來cat是沒有showName() 方法,現在是把animal 的showName()方法放到catshow而cat的this.name是Cat。所以this.name 應該是 Cat

實作繼承

function Animal(name){
this.name = name;
this.showName = function(){ alert(this.name);}
}
function Cat(name){ Animal.call(this, name); }
var cat = new Cat("Black Cat");
cat.showName();

   

  Animal.call(this) 的意思是呼叫Animal方法,但是使用 this 物件取代了物件,上下文環境物件是變成物件環境的意思就是變成了物件。 new Cat("Black Cat")中使用Animal.call為目前的上下文環境設定了屬性name和方法showName。

拓展:多重繼承

function Class10(){
this.showSub = function(a,b){ alert(a-b); }
}
function Class11(){
this.showAdd = function(a,b){ alert(a+b); }
}
function Class2(){
Class10.call(this);
Class11.call(this);
}

   

  備註:js的繼承還有其他方法,例如使用原型鏈,這個不屬於本文的範疇,只是在此說明call 的用法。說了call ,當然還有 apply,這兩個方法基本上是一個意思,區別在於 call 的第二個參數可以是任意類型,而apply的第二個參數必須是數組或arguments。

b.arguments使用

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

什麼是arguments

  arguments 是是JavaScript裡的內建對象,它很古怪,也常被人忽視,但其實是很重要的。所有主要的js函數庫都利用了arguments物件。所以agruments物件對於javascript程式設計師來說是必需熟悉的。

  所有的函數都有屬於自己的一個arguments對象,它包含了函所要呼叫的參數。他不是一個數組,如果用typeof arguments,回傳的是'object'。雖然我們可以用呼叫資料的方法來呼叫arguments。例如length,還有index方法。但數 組的push和pop物件是不適用的。

使用arguments創建一個靈活的函數

  看起來貌似argument物件使用起來十分有限,但是實際上它是一個非常有用的物件。你可以透過使用argument物件讓函數能夠呼叫數量不定 的參數。在Dean Edwards的base2函式庫裡有個格式化的函數,展現了這個彈性。

function format(string) {
var args = arguments;
var pattern = new RegExp('%([1-' + arguments.length + '])', 'g');
return String(string).replace(pattern, function(match, index,position,all) {
console.log(match + '&' + index + '&' + position + '&' + all);
return args[index];
});
};

   

  掉用format('And the %1 want to know whose %2 you %3', 'papers', 'shirt', 'wear');結果為" papers shirt you wear";控制台打印為

  %1&1&8&And the %1 want to know whose %2 you %3
  %2&2&30&And the %1 want to knownow %2 %2&2&30&And the %1 want to knownow% 2  %2&2&30&And the %1 want to knowose %2   7% 30&And"]%1 want tonow whose %2 you %3

把arguments物件轉換成一個真正的陣列


  雖然arguments物件不是一個真正的javascript數組,但是我們還是可以輕易的把它轉換成標準的數據,然後進行數組操作。

var args = Array.prototype.slice.call(arguments);

   

  那麼現在這個變數args含有一個含有函數所有參數的標準javascript陣列物件。


拓展:使用上一節的format函數,透過預置的arguments物件建立函數

function makeFunc() {
var args = Array.prototype.slice.call(arguments);
var func = args.shift();
return function() {
return func.apply(null, args.concat(Array.prototype.slice.call(arguments)));
};
}

   

  該方法會將第一個參數取出來,然後傳回一個參數的參數(第二個arguments)將會和makeFunc的從第二個參數開始的參數組合成新數組。並回傳makeFunc第一個參數的apply呼叫


  執行

var majorTom = makeFunc(format, "This is Major Tom to ground control. I'm %1.");
majorTom("stepping through the door");

   

  結果為:"This s Major Tomor to ground control。 % 1&1&41&This is Major Tom to ground control. I'm %1.


[function.]arguments.callee

  说明:arguments.callee方法返回的是正在执行的函数本身。

  callee 属性是 arguments 对象的一个成员,它表示对函数对象本身的引用,这有利于匿名函数的递归或者保证函数的封装性,例如下边示例的递归计算1到n的自然数之和。而该属性仅当相关函数正在执行时才可用。还有需要注意的是callee拥有length属性,这个属性有时候用于验证还是比较好的。arguments.length是实参长度,arguments.callee.length是形参(定义时规定的需要的参数)长度,由此可以判断调用时形参长度是否和实参长度一致。

//用于验证参数
function calleeLengthDemo(arg1, arg2) {
if (arguments.length==arguments.callee.length) {
window.alert("验证形参和实参长度正确!");
return;
} else {
alert("实参长度:" +arguments.length);
alert("形参长度: " +arguments.callee.length);
}
}
//递归计算
var sum = function(n){
if (n <= 0) return 1;
else return n +arguments.callee(n - 1)
}
//比较一般的递归函数:
var sum = function(n){
if (1==n) return 1;
else return n + sum (n-1);
}

   

  调用时:alert(sum(100));其中函数内部包含了对sum自身的引用,函数名仅仅是一个变量名,在函数内部调用sum即相当于调用一个全局变量,不能很好的体现出是调用自身,这时使用callee会是一个比较好的方法。

拓展 functionName.caller 

  说明: 返回是谁调用了functionName 函数。functionName 对象是所执行函数的名称。对于函数来说,caller 属性只有在函数执行时才有定义。如果函数是由顶层调用的,那么 caller 包含的就是 null 。如果在字符串上下文中使用 caller 属性,那么结果和 functionName.toString 一样,也就是说,显示的是函数的反编译文本。 下面的例子说明了 caller 属性的用法:

// caller demo {
function callerDemo() {
if (callerDemo.caller) {
var a= callerDemo.caller.toString();
alert(a);
} else {
alert("this is a top function");
}
}
function handleCaller() {
callerDemo();
}
handleCaller();

   

  执行结果:

JS中call/apply、arguments、undefined/null方法詳解

c.undefined和null

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

  大多数计算机语言,有且仅有一个表示"无"的值,比如,C语言的NULL,Java语言的null,Python语言的none,Ruby语言的nil。有点奇怪的是,JavaScript语言居然有两个表示"无"的值:undefined和null。这是为什么?

相似性

  在JavaScript中,将一个变量赋值为undefined或null,老实说,几乎没区别。

  代码如下:

var a = undefined;
var a = null;

   

  上面代码中,a变量分别被赋值为undefined和null,这两种写法几乎等价。

  undefined和null在if语句中,都会被自动转为false,相等运算符甚至直接报告两者相等。

if (!undefined)
console.log(&#39;undefined is false&#39;);
// undefined is false
if (!null)
console.log(&#39;null is false&#39;);
// null is false
undefined == null
// true

   

  上面代码说明,两者的行为是何等相似!但是我们去查看undefined和null的各自的类型却发现类型是不同的。js基础类型中没有null类型

typeof null;//"object"
typeof undefined;//"undefined"

   

  既然undefined和null的含义与用法都差不多,为什么要同时设置两个这样的值,这不是无端增加JavaScript的复杂度,令初学者困扰吗?Google公司开发的JavaScript语言的替代品Dart语言,就明确规定只有null,没有undefined!

历史原因

  原来,这与JavaScript的历史有关。1995年JavaScript诞生时,最初像Java一样,只设置了null作为表示"无"的值。

  根据C语言的传统,null被设计成可以自动转为0。

Number(null) // 0
5 + null // 5

  但是,JavaScript的设计者Brendan Eich,觉得这样做还不够,有两个原因。

  首先,null像在Java里一样,被当成一个对象。

typeof null // "object"

  但是,JavaScript的数据类型分成原始类型(primitive)和合成类型(complex)两大类,Brendan Eich觉得表示"无"的值最好不是对象。

  其次,JavaScript的最初版本没有包括错误处理机制,发生数据类型不匹配时,往往是自动转换类型或者默默地失败。Brendan Eich觉得,如果null自动转为0,很不容易发现错误。因此,Brendan Eich又设计了一个undefined。

最初设计

  JavaScript的最初版本是这样区分的:null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。

Number(undefined) // NaN
5 + undefined // NaN 

目前的用法

  但是,上面这样的区分,在实践中很快就被证明不可行。目前,null和undefined基本是同义的,只有一些细微的差别。

  null表示"没有对象",即该处不应该有值。典型用法是:

  (1) 作为函数的参数,表示该函数的参数不是对象。

  (2) 作为对象原型链的终点。

Object.getPrototypeOf(Object.prototype) // null

  undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:

  (1)变量被声明了,但没有赋值时,就等于undefined。

  (2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。

  (3)对象没有赋值的属性,该属性的值为undefined。

  (4)函数没有返回值时,默认返回undefined。

var i;
i // undefined
function f(x){console.log(x)}
f() // undefined
var o = new Object();
o.p // undefined
var x = f();
x // undefined

   

以上所述是小编给大家介绍的JS中call/apply、arguments、undefined/null方法詳解,希望对大家有所帮助。

更多JS中call/apply、arguments、undefined/null方法詳解相关文章请关注PHP中文网!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn