摘要:方法真是一個有意思的東西,它可以改變函數調用時的值。所以前面的說法其實不對,所有的對象都可以被視為類數組,有的視為長度為的數組,沒有的,視為長度為的數組。
call方法真是一個有意思的東西,它可以改變函數調用時this的值。而我們知道,在函數里,this指向了調用這個函數的環境對象,比如一道經典面試題:
var num = 2; var obj = { num: 1, show: function () { console.log(this.num) } }; var foo = obj.show; obj.show();/* 顯示1;show是被obj調用的,所以this指向obj */ foo();/* 顯示2;相當于global.foo(),所以this指向global,如果在瀏覽器里global就是window */
換句話說,如果一個對象obj上有方法foo,你可以通過obj.foo()調用;如果沒有obj上沒有方法foo,obj.foo()是會報錯的,但是,使用foo.call(obj),可以強行達到obj.foo()的效果,比如:
function foo(){ console.log(this.num); } var obj = { num: 1 } foo.call(obj);// 1
Array.prototype.slice.call的用處就是這樣,可以在array-like(類數組,就是長得像數組,但不是數組)的對象上強行使用slice方法,比如:Array.prototype.slice.call(arguments)就是把arguments對象轉化為數組。當然,除了arguments,我們還能在HTMLCollection或NodeList身上使用。那么到底什么算是類數組呢?
有length屬性的對象。
比如:
var obj1 = { 0: "Tom", 1: "Jack", 2: "Jason", length: 3 } var arr = [].slice.call(obj1); console.log("arr: ", arr);/* [ "Tom", "Jack", "Jason" ] */
那如果沒有length呢?
var obj1 = { 0: "Tom", 1: "Jack", 2: "Jason" } var arr = [].slice.call(obj1);//* [] */
原來沒有length屬性的對象也會被轉為數組,只不過認為它length=0而已。
那如果對象的屬性沒有按照0-n順序乖乖排好呢?
var obj1 = { 1: "Tom", 3: "Jack", 5: "Jason", 7: "Dave", foo: "bar", length: 6 } var arr = [].slice.call(obj1);/* [ , "Tom", , "Jack", , "Jason" ] */
原來轉化的時候,會以length為基礎,生成一個長度為length的數組,obj的屬性是數組的有效index的話,就會把對應值填入到對應位置,其他的位置找不到值,就會填入undefined。
所以前面的說法其實不對,所有的對象都可以被視為類數組,有length的視為長度為length的數組,沒有的,視為長度為0的數組。
以length屬性為基礎
這句話很重要。
另外,call方法的參數如果是原始值類型,會傳入它的自動包裝對象:
var arr = [].slice.call("hello");
等價于:
var arr = [].slice.call(new String("hello"));/* [ "h", "e", "l", "l", "o" ] */ 因為new String("hello")就是 { 0: "h", 1: "e", 2: "l", 3: "l", 4: "o", length: 5 }
以上就是Array.prototype.slice.call的一些細節,那么除了slice之外,Array對象還有很多其他的方法,這些方法是不是也能用到對象身上呢?
Array.prototype.joinjoin方法是把數組轉化為字符串的方法,具體表現不再贅述,看兩個例子:
var obj1 = { 0: "Tom", 1: "Jack", 2: "Jason", length: 6 } var arr = [].join.call(obj1, "-");// Tom-Jack-Jason--- var obj1 = { 0: "Tom", 1: "Jack", 2: "Jason", } var arr = [].join.call(obj1, "-"); // ""
還是那句話,以length為基礎,沒有length屬性的,視為長度為0的數組。
Array.prototype.push這個方法比較好玩:
var obj1 = { 0: "Tom", 1: "Jack", 2: "Jason", length: 6 } var arr = [].push.call(obj1, "Dave"); console.log("arr: ", arr);// 7,因為push方法返回的是push之后array的操作數 console.log("obj: ", obj1);// { "0": "Tom", "1": "Jack", "2": "Jason", "6": "Dave", length: 7 }
可以看到obj1里新增屬性6,值為"Dave",并且length也更新為7,這說明調用push時會對原有對象進行修改。
我們可以利用這個特性,比如當我們需要一個obj1的類數組副本時:
var obj = { foo: "foo", bar: "bar", cei: "cei" }; var copy = {}; for (var i in obj) { [].push.call(copy, obj[i]) } console.log(copy);// { "0": "foo", "1": "bar", "2": "cei", length: 3 }
如果,沒有傳入length呢?
var obj1 = { 0: "Tom", 1: "Jack", 2: "Jason" } var arr = [].push.call(obj1, "Dave"); console.log("arr: ", arr);// 1 console.log("obj: ", obj1);// { "0": "Dave", "1": "Jack", "2": "Jason", length: 1 }
這里的行為有些詭異,不過也更好地解釋了以length為基礎這句話:
沒有length的時候,認為數組長度為0,并且會對obj進行修改,把屬性0的值改為Dave.
那么,會舉一反三的話,對于pop, shift和unshift這三個方法的行為應該能想象得出來,就不再贅述了。
Array.prototype.reversevar obj1 = { 0: "Tom", 1: "Jack", 2: "Jason", length: 6 } var arr = [].reverse.call(obj1); console.log("arr: ", arr);// { "3": "Jason", "4": "Jack", "5": "Tom", length: 6 } console.log("obj: ", obj1);// { "3": "Jason", "4": "Jack", "5": "Tom", length: 6 }
reverse的話,arr === obj1
Array.prototype.sortvar obj1 = { 0: "c", 1: "b", 2: "a", length: 6 } var arr = [].sort.call(obj1); console.log("arr: ", arr);// { "0": "a", "1": "b", "2": "c", length: 6 } console.log("obj: ", obj1);// { "0": "a", "1": "b", "2": "c", length: 6 }
sort也一樣,arr === obj1
Array.prototype.concatconcat的表現就不是我們意料之中的了:
var obj1 = { 0: "c", 1: "b", 2: "a", length: 6 } var add = { foo: "foo", bar: "bar" } var arr = [].concat.call(obj1, add); console.log("arr: ", arr);// [ { "0": "c", "1": "b", "2": "a", length: 6 }, "foo", "bar" ] console.log("obj: ", obj1);// { "0": "c", "1": "b", "2": "a", length: 6 }
var obj1 = { 0: "c", 1: "b", 2: "a", length: 6 } var arr = [].concat.call(obj1, "foo", "bar"); console.log("arr: ", arr);// [ { "0": "c", "1": "b", "2": "a", length: 6 }, "foo", "bar" ] console.log("obj: ", obj1);// { "0": "c", "1": "b", "2": "a", length: 6 }
可以看到obj1并不會改變,不會像push一樣會接著形成一個類數組的對象.
Array.prototype.splicevar obj1 = { 0: "c", 1: "b", 2: "a", length: 6 } var arr = [].splice.call(obj1, 0, 1); console.log("arr: ", arr);// [ "c" ] console.log("obj: ", obj1);// { "0": "b", "1": "a", length: 5 }
var obj1 = { 0: "c", 1: "b", 2: "a", length: 6 } var arr = [].splice.call(obj1, 1, 0, "foo","bar"); console.log("arr: ", arr);// [] console.log("obj: ", obj1);// { "0": "c", "1": "foo", "2": "bar", "3": "b", "4": "a", length: 8 }
var obj1 = { 0: "c", 1: "b", 2: "a", length: 6 } var arr = [].splice.call(obj1, 1, 1, "foo","bar"); console.log("arr: ", arr);// [ "b" ] console.log("obj: ", obj1);// { "0": "c", "1": "foo", "2": "bar", "3": "a", length: 7 }
splice的行為回歸了,它現在對obj1產生影響,并且是我們預計的樣子
Array.prototype.everyvar obj1 = { 0: "c", 1: "b", 2: "a", length: 6 } var arr = [].every.call(obj1, function (val) { return val === "a" || val === "c" }); console.log("arr: ", arr);// false console.log("obj: ", obj1);// { "0": "c", "1": "b", "2": "a", length: 6 }Array.prototype.filter
var obj1 = { 0: "c", 1: "b", 2: "a", length: 6 } var arr = [].filter.call(obj1, function (val) { return val === "a" || val === "c" }); console.log("arr: ", arr);// [ "c", "a" ] console.log("obj: ", obj1);// { "0": "c", "1": "b", "2": "a", length: 6 }Array.prototype.forEach
var obj1 = { 0: "c", 1: "b", 2: "a", length: 6 } var arr = [].forEach.call(obj1, function (val) { return val + " add"; }); console.log("arr: ", arr);// undefined console.log("obj: ", obj1);// { "0": "c", "1": "b", "2": "a", length: 6 }Array.prototype.map
var obj1 = { 0: "c", 1: "b", 2: "a", length: 6 } var arr = [].map.call(obj1, function (val) { return val + " add"; }); console.log("arr: ", arr);// [ "c add", "b add", "a add", , , ] console.log("obj: ", obj1);// { "0": "c", "1": "b", "2": "a", length: 6 }Array.prototype.reduce
var obj1 = { 0: "c", 1: "b", 2: "a", length: 6 } var arr = [].reduce.call(obj1, function (pre, cur) { return pre + " " + cur }); console.log("arr: ", arr);// "c b a" console.log("obj: ", obj1);// { "0": "c", "1": "b", "2": "a", length: 6 }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82349.html
摘要:在閱讀的過程中,發現了它的一些小技巧,對我們平時的編程很有用。事實上,在上也的確是可以被更改的而在或高版本的中,并不能更改全局的。但是,局部的仍然可以被改變。所以,建議在已知長度的情況下,使用第一種,而不知道長度的情況下,使用第二種。 在閱讀 underscore 的過程中,發現了它的一些小技巧,對我們平時的編程很有用。在這里向大家介紹一二 void 0 代替 underfined 首...
摘要:很簡單,不是數組,但是有屬性,且屬性值為非負類型即可。至于屬性的值,給出了一個上限值,其實是感謝同學指出,因為這是中能精確表示的最大數字。如何將函數的實際參數轉換成數組 這篇文章拖了有兩周,今天來跟大家聊聊 JavaScript 中一類特殊的對象 -> Array-Like Objects。 (本文節選自 underscore 源碼解讀系列文章,完整版請關注 https://githu...
摘要:不能應用下的等方法。首先我們可以通過給目標函數指定作用域來簡單實現方法保存,即調用方法的目標函數考慮到函數柯里化的情況,我們可以構建一個更加健壯的這次的方法可以綁定對象,也支持在綁定的時候傳參。原因是,在中,多次是無效的。 bind 是返回對應函數,便于稍后調用;apply 、call 則是立即調用 。 apply、call 在 javascript 中,call 和 apply 都是...
摘要:首先我們可以通過給目標函數指定作用域來簡單實現方法保存,即調用方法的目標函數考慮到函數柯里化的情況,我們可以構建一個更加健壯的這次的方法可以綁定對象,也支持在綁定的時候傳參。原因是,在中,多次是無效的。而則會立即執行函數。 bind 是返回對應函數,便于稍后調用;apply 、call 則是立即調用 。 apply、call 在 javascript 中,call 和 apply 都是...
摘要:定義類數組對象的定義可以通過索引訪問元素,并且擁有屬性沒有數組的其他方法,例如,,等。所以當后面的作用對象是一個類數組時,就會把這個類數組對象轉換為了一個新的數組。 定義 JavaScript 類數組對象的定義: 可以通過索引訪問元素,并且擁有 length 屬性; 沒有數組的其他方法,例如 push , forEach , indexOf 等。 舉例說明 var foo = {...
閱讀 2830·2021-11-24 09:39
閱讀 4082·2021-10-27 14:19
閱讀 2043·2021-08-12 13:25
閱讀 2334·2019-08-29 17:07
閱讀 1112·2019-08-29 13:44
閱讀 1066·2019-08-26 12:17
閱讀 462·2019-08-23 17:16
閱讀 2048·2019-08-23 16:46