apply()
Function.prototype.apply()將會呼叫一個以this和陣列形式的arguments為引數的方法。
m
fun.apply(thisArg,[argsArray])
每當要為一個新的物件新增一個方法時,有時不得不為其重寫一個方法。而如果利用apply的話,只需要寫一次方法,然後在這個新的物件中繼承它即可,十分方便。
apply和call方法十分相似,僅僅只是引數不同而已,但正是因為這一點,我們在用apply時不必知道被呼叫的物件的具體引數,可以只穿arguments,如此一來,被呼叫的這個物件將負責handle觸底的arguments。
1.我們可以像Java那樣,利用apply為一個物件建立構造鏈。在下面的例子中,我們將建立一個名為construct的全域性方法,這個方法可以不必讓你傳遞一個一個的引數,取而代之的則是傳遞一個引數陣列。當地一個引數為null時,指向的時window物件。
// Function.prototype.construct = function(aArgs) {
// var oNew = Object.create(this.prototype);
// this.apply(oNew, aArgs);
// return oNew;
// };
//Function.prototype.construct = function(aArgs) {
// var fConstructor = this, fNewConstr = function() {
// fConstructor.apply(this, aArgs);
// };
// fNewConstr.prototype = fConstructor.prototype;
// return new fNewConstr();
//};
Function.prototype.construct = function (aArgs) {
var fNewConstr = new Function("");
fNewConstr.prototype = this.prototype;
var oNew = new fNewConstr();
this.apply(oNew, aArgs);
return oNew;
};
function MyConstructor() {
for (var nProp = 0; nProp < arguments.length; nProp++) {
this[`property` + nProp] = arguments[nProp];
}
}
var myArray = [4, `Hello world!`, false];
var myInstance = MyConstructor.construct(myArray);
console.log(myInstance.property1); // logs `Hello world!`
console.log(myInstance instanceof MyConstructor); // logs `true`
console.log(myInstance.constructor);
function minOfArray(arr){
var min = Infinity;
var QUANTUM = 32768;
var len=arr.length;
for(var i=0;i<len;i+=QUANTUM){
var submin = Math.min.apply(null,arr.slice(i,Math.min(i+QUANTUM,len)));
min = Math.min(submin,min)
}
return min;
}
var min = minOfArray([5,6,2,3,7]);
console.log(min)//2
function Person(name,age)
{
this.name=name;
this.age=age;
}
/*定義一個學生類*/
function Student(name,age,grade)
{
Person.apply(this,arguments);
this.grade=grade;
}
//建立一個學生類
var student=new Student("zhangsan",21,"一年級");
//測試
alert("name:"+student.name+"
"+"age:"+student.age+"
"+"grade:"+student.grade);
call()
call()方法呼叫一個函式,其具體有一個指定的this值和分別地提供的引數。
注意:
該方法的作用和apply()方法類似,只有一個區別,就是call()方法接受的是若干個引數的列表,而apply()方法接受的是一個包含多個引數的陣列。
fun.call(thisArg,arg1,arg2,…)
引數:
在fun函式執行時指定的是this值。需要注意的是,指定的this值並不一定是該函式執行時真正的this值,如果這個函式處於非嚴格模式下,則指定為null和undefinde的this值會自動指向全域性物件,同時值為原始值(數字,字串,布林值)的this會指向該原始值的自動包裝物件。
arg1,arg2指定的引數列表。
返回值:
返回值是你呼叫的方法的返回值,若該方法沒有返回值,則返回undefined。
call()允許為不同的物件分配和呼叫屬於一個物件的函式/方法。
可以讓call()中的物件呼叫當前物件所擁有的function。你剋以使用call()來實現繼承:寫一個方法,然後讓另一個新的物件來繼承它。
function Product(name,price){
this.name = name;
this.price = price;
}
function Food(name,price){
Product.call(this,name,price);
this.category = `food`
}
console.log(new Food(`cheese`,5).name)//cheese
//在一個子勾走函式中,你可以通過呼叫父建構函式的call方法來實現繼承,類似於Java中的寫法。下例中,使用Food和Toy建構函式建立的物件示例都會擁有Product建構函式中新增的name屬性和price屬性,但category屬性是在各自的建構函式中定義的。
function Food(name, price) {
this.name = name;
this.price = price;
if (price < 0) {
throw RangeError(
`Cannot create product ` + this.name + ` with a negative price`
);
}
this.category = `food`;
}
//function Toy 同上
function Toy(name, price) {
Product.call(this, name, price);
this.category = `toy`;
}
var cheese = new Food(`feta`, 5);
var fun = new Toy(`robot`, 40);
使用call方法呼叫匿名函式。
在下例中的for迴圈體內,我們建立了一個匿名函式,然後通過呼叫該函式的call方法,將每個陣列元素作為指定的this執行了那個匿名函式。這個匿名函式的主要目的是給每個陣列元素物件新增一個print方法,這個print方法可以列印出各元素在陣列中的正確索引號。當然,這裡不是必須得讓陣列元素作為this值傳入那個匿名函式,目的是為了演示call的用法。
var animals = [
{species:`Lion`,name:`King`},
{species:`Whale`,name:`Fail`}
];
for(var i=0;i<animals.length;i++){
(function(i){
this.print = function(){
console.log(`#`+i+``+this.species+`:`+this.name);
}
this.print();
}).call(animals[i],i)
}
使用call方法呼叫函式並且指定上下文的this
在下面的例子中,當呼叫greet方法的時候,該方法的this值會繫結到i物件。
function greet(){
var reply = [this.person,`Is An Awesome`,this.role].join(``);
console.log(reply);
}
var i = {
person:`Douglas Crockford`,
role:`JavaScript DeveLoper`
}
greet.call(i);// Douglas Crockford Is An Awesome Javascript Developer
bind()
bind()方法建立一個新的函式,當這個新函式被呼叫時this鍵值為其提供的值,其引數列表前幾項值為建立時指定的引數序列。
語法:
fun.bind(thisArg[,arg1[,arg2[,...]]])
引數:
thisArg呼叫繫結函式時作為this引數傳遞給目標函式的值。如果使用new運算子構造繫結函式,則忽略該值。當使用bind在setTimeout中建立一個函式(作為回撥提供)時,作為thisArg傳遞的任何原始值都將轉換為object。如果沒有提供繫結的引數,則執行作用域的this被視為新函式的thisArg
arg1,arg2,...當繫結函式被呼叫時,這些引數將置於實參之前傳遞給被繫結的方法。
返回值:
返回由指定的this值和初始化引數改造的原函式拷貝。
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
console.log(module.getX()); // 返回 81
var retrieveX = module.getX.bind(module);
console.log(retrieveX()); // 返回 9, 在這種情況下,"this"指向全域性作用域
// 建立一個新函式,將"this"繫結到module物件
// 新手可能會被全域性的x變數和module裡的屬性x所迷惑
var boundGetX = retrieveX.bind(module);
console.log(boundGetX()); // 返回 81
var o={
f:function(){
var self = this;
var fff = function(){
console.log(self.value)//此時this指向的是全域性作用域,因此需要使用self指向物件o
};
fff();
},
value:`Hello World`
};
o.f()//Hello World!
上例子是我們常用了保持this上下文的方法,把this賦值給了中間變數self,這樣在內部巢狀的函式中能夠使用self訪問到物件o,否則仍使用this.value,內部巢狀函式的this此時指向的是全域性作用域,最後的輸出將會是undefined。
但是,如果我們使用bind()函式,將fff函式的繫結在物件o中,即將fff()函式內部的this物件繫結為物件o,那麼可以遇見此時this.value是存在的。程式碼如下:
var o={
f:function(){
var self = this;
var fff = function(){
console.log(this.value);
}.bind(this);
fff();
}
valeu:"Hello World!"
}
o.f()//Hello World!
更普通的使用情形:
function f(y,z){
return this.x+y+z;
}
var m = f.bind({X;1},2);
console.log(m(3))
最後將輸出6
這是因為bind()方法會把傳入它的第一個實參繫結給f函式體的this,從第二個實參起,將依次傳遞給原始函式,因此{x:1}傳遞給this,2傳遞給形參y,m(3)呼叫時的3傳遞給形參z.