函數的四種調用方式
函數有下列調用模式
- 函數調用模式
- 方法調用模式
- 構造器模式
- 上下文模式
1. 函數調用 模式
要調用,就肯定要先定義,函數的定義方式:
- 聲明式: function fuc() {}
- 表達式式: var func = function() {};
- Function: new Function( ‘參數’,…,’函數體’ );
單獨獨立調用的,就是函數調用模式,即 函數名( 參數 ),不能加任何其他的東西, 對象 o.fuc() 就不是了。
在函數調用模式中, this 表示全局對象 window
任何自調用函數都是函數模式。
2. 方法調用 模式 method
所謂方法調用,就是用對象的方法調用。方法是什么,方法本身就是函數,但是,方法不是單獨獨立的,而是要通過一個對象引導來調用。
就是說方法對象一定要有宿主對象。
即 對象.方法(參數)
this表示引導方法的對象,就是指宿主對象
對比-函數調用模式:
- 方法調用模式是不是獨立的,需要宿主,而函數調用模式是獨立的
- 方法調用模式方式:obj.fuc(); 函數調用模式方式: fuc();
- 方法調用模式中,this指宿主。而函數調用模式中 this 指 全局對象window
美團的一道面試題
-
var length = 10;
-
function fn() {
-
console.log( this.length ); // 10
-
}
-
var obj = {
-
length: 5,
-
method: function ( fn ) {
-
fn(); // 10 前面沒有引導對象,是函數調用模式
-
arguments[ 0 ](); // 2
-
// arguments是一個偽數組對象, 這里調用相當於通過數組的索引來調用.
-
// 這里 this 就是 指的這個偽數組, 所以 this.length 為 2
-
}
-
};
-
obj.method( fn, 1 ); // 打印 10 和 2
-
//obj.method( fn, 1, 2, 3 ); // 打印 10 和 4
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
解析:
-
fn() 前面沒有引導對象,是函數調用模式, this是全局對象,輸出 10
-
arguments[ 0 ](),arguments是一個偽數組對象, 這里調用相當於通過數組的索引來調用.
這里引導對象即宿主就是 arguments對象。
所以,執行時,this 就是指 arguments,由於傳了兩個參數,所以 輸出為 arguments.length 就是 2
3. 構造器模式(構造函數模式, 構造方法模式)
constructor
-
特點: 使用 new 關鍵字引導
-
執行步驟:var p = new Person();
new 是一個運算符, 專門用來申請創建對象, 創建出來的對象傳遞給構造函數的 this。然后利用構造函數對其初始化。
-
function Person () {
-
// new了 進入構造函數時, p 對象的原型 就指向了 構造函數 Person,
-
// p.__proto__.constructor = function Person() {};
-
// 而 this 指的的是 p 對象
-
this.name = 'jim',
-
this.age = 19;
-
this.gender = 'male';
-
}
-
var p = new Person();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
執行完 new 進入構造函數時, p 對象的原型 就指向了 構造函數 Person
而 構造時,this 指的的是 p 對象,是通過對象動態添加屬性來構造的
小貼士:如果調用構造函數的時候, 構造函數沒有參數, 圓括號是可以省略的。
-
function Person() {
-
this.name = 'jim';
-
}
-
var p = new Person; // 不傳參,可以簡寫,不影響構造
-
console.log( p ); // p 含有 name屬性
- 1
- 2
- 3
- 4
- 5
↑ 不傳參,可以簡寫,不影響構造
-
-
返回值
-
不寫 return 語句, 那么 構造函數 默認返回 this
-
在構造函數 return 基本類型( return num, return 1223 ). 則忽略返回類型.
-
在構造函數 return 引用類型, 那么構造函數返回該引用類型數據, 而忽略 this
-
function Person () {
-
this.name = 'Jepson';
-
return 123;
-
}
-
var p1 = new Person();
-
console.log( p1 );
- 1
- 2
- 3
- 4
- 5
- 6
↑ 忽略了 123,返回 this 對象, 指向構建的實例
-
function Person () {
-
this.name = 'Jepson';
-
return { 'peter': 'nihao' };
-
}
-
var p1 = new Person();
-
console.log( p1 );
- 1
- 2
- 3
- 4
- 5
- 6
↑ 忽略了 this,返回 { ‘peter’: ‘nihao’ } 對象
-
構造函數結合性
-
如果構造函數沒有參數, 可以省略 圓括號
var p = new Person;
-
如果希望創建對象並直接調用其方法
( new Person () ).sayHello()
-> 可以省略調整結核性的圓括號 new Person().sayHello()
-> 如果想要省略構造函數的圓括號, 就必須添加結核性的圓括號 (new Person).sayHello()
面試題
一道面試題,大家可以自己嘗試先做一下,再看下面的答案和解析
請問順序執行下面代碼,會怎樣 alert
-
function Foo(){
-
getName = function(){ alert(1); };
-
return this;
-
}
-
Foo.getName = function(){ alert(2); };
-
Foo.prototype.getName = function(){ alert(3); };
-
var getName = function(){ alert(4); };
-
function getName(){ alert(5); }
-
-
Foo.getName(); // alert ??
-
getName(); // alert ??
-
Foo().getName(); // alert ??
-
getName(); // alert ??
-
new Foo.getName(); // alert ??
-
new Foo().getName(); // alert ??
-
new new Foo().getName(); // alert ??
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
預解析,簡化后的代碼,以及答案
-
/* function getName(){ alert(5); } 執行到下面被覆蓋了,直接刪除 */
-
function Foo() {
-
getName = function () { alert(1); };
-
return this;
-
}
-
Foo.getName = function () { alert(2); };
-
Foo.prototype.getName = function () { alert(3); };
-
var getName = function () { alert(4); };
-
-
Foo.getName(); // ------- 輸出 2 -------
-
getName(); // ------- 輸出 4 -------
-
Foo().getName(); // ------- 輸出 1 -------
-
getName(); // ------- 輸出 1 -------
-
new Foo.getName(); // ------- 輸出 2 -------
-
new Foo().getName(); // ------- 輸出 3 -------
-
var p = new new Foo().getName(); // ------- 輸出 3 -------
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
全部解析過程 ↓
-
function Foo() {
-
getName = function () { alert(1); };
-
return this;
-
}
-
Foo.getName = function () { alert(2); };
-
Foo.prototype.getName = function () { alert(3); };
-
var getName = function () { alert(4); };
-
-
Foo.getName(); // ------- 輸出 2 -------
-
// 調用 Foo函數 作為 對象 動態添加的屬性方法 getName
-
// Foo.getName = function () { alert(2); };
-
-
getName(); // ------- 輸出 4 -------
-
// 這里 Foo函數 還沒有執行,getName還沒有被覆蓋
-
// 所以 這里還是 最上面的 getName = function () { alert(4); };
-
-
Foo().getName(); // ------- 輸出 1 -------
-
// Foo()執行,先覆蓋全局的 getName 再返回 this,
-
// this 是 window, Foo().getName() 就是調用 window.getName
-
// 此時 全局的 getName已被覆蓋成 function () { alert(1); };
-
// 所以 輸出 1
-
/* 從這里開始 window.getName 已被覆蓋 alert 1 */
-
-
getName(); // -------- 輸出 1 --------
-
// window.getName alert(1);
-
-
new Foo.getName(); // ------- 輸出 2 -------
-
// new 就是 找 構造函數(),由構造函數結合性,這里即使 Foo無參,也不能省略 (),所以不是 Foo().getName()
-
// 所以 Foo.getName 為一個整體,等價於 new (Foo.getName)();
-
// 而 Foo.getName 其實就是函數 function () { alert(2); } 的引用
-
// 那 new ( Foo.getName )(), 就是在以 Foo.getName 為構造函數 實例化對象。
-
// 就 類似於 new Person(); Person 是一個構造函數
-
-
// 總結來看 new ( Foo.getName )(); 就是在以 function () { alert(2); } 為構造函數來構造對象
-
// 構造過程中 alert( 2 ),輸出 2
-
-
new Foo().getName(); // ------- 輸出 3 -------
-
// new 就是 找 構造函數(),等價於 ( new Foo() ).getName();
-
// 執行 new Foo() => 以 Foo 為構造函數,實例化一個對象
-
// ( new Foo() ).getName; 訪問這個實例化對象的 getName 屬性
-
// 實例對象自己並沒有 getName 屬性,構造的時候也沒有 添加,找不到,就到原型中找
-
// 發現 Foo.prototype.getName = function () { alert(3); };
-
// 原型中有,找到了,所以 ( new Foo() ).getName(); 執行,alert(3)
-
-
var p = new new Foo().getName(); // ------- 輸出 3 -------
-
// new 就是 找 構造函數(),等價於 new ( ( new Foo() ).getName )() 輸出 3
-
-
// 先看里面的 ( new Foo() ).getName
-
// new Foo() 以Foo為構造函數,實例化對象
-
// new Foo().getName 找 實例對象的 getName屬性,自己沒有,去原型中找,
-
// 發現 Foo.prototype.getName = function () { alert(3); }; 找到了
-
-
// 所以里層 ( new Foo() ).getName 就是 以Foo為構造函數實例出的對象的 一個原型屬性
-
// 屬性值為一個函數 function () { alert(3); } 的引用
-
-
// 所以外層 new ( (new Foo()).getName )()在以該函數 function () { alert(3); } 為構造函數,構造實例
-
// 構造過程中 執行了 alert(3), 輸出 3
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
4. 上下文調用模式
就是 環境調用模式 => 在不同環境下的不同調用模式
簡單說就是統一一種格式, 可以實現 函數模式與方法模式
-> 語法(區分)
- call 形式, 函數名.call( … )
- apply 形式, 函數名.apply( … )
這兩種形式功能完全一樣, 唯一不同的是參數的形式. 先學習 apply, 再來看 call 形式
apply方法的調用形式
存在上下文調用的目的就是為了實現方法借用,且不會污染對象。
-
如果需要讓函數以函數的形式調用, 可以使用
foo.apply( null ); // 上下文為 window
-
如果希望他是方法調用模式, 注意需要提供一個宿主對象
foo.apply( obj ); // 上下文 為 傳的 obj 對象
-
function foo () {
-
console.log( this );
-
}
-
var o = { name: 'jim' };
-
-
// 如果需要讓函數以函數的形式調用, 可以使用
-
foo.apply( null ); // this => window // 或 foo.apply()
-
-
// 如果希望他是方法調用模式, 注意需要提供一個宿主對象
-
foo.apply( o ) // this => o 對象
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
帶有參數的函數如何實現上下文調用?
-
function foo ( num1, num2 ) {
-
console.log( this );
-
return num1 + num2;
-
}
-
-
// 函數調用模式
-
var res1 = foo( 123, 567 );
-
-
// 方法調用
-
var o = { name: 'jim' };
-
o.func = foo;
-
var res2 = o.func( 123, 567 );
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
使用 apply 進行調用, 如果函數是帶有參數的. apply 的第一個參數要么是 null 要么是對象
-
如果是 null 就是函數調用
-
如果是 對象就是 方法調用, 該對象就是宿主對象, 后面緊跟一個數組參數, 將函數所有的參數依次放在數組中.
-
例如: 函數模式 foo( 123, 567 );
-
apply foo.apply( null, [ 123, 567 ] ) 以 window 為上下文執行 apply
-
-
如果有一個函數調用: func( '張三', 19, '男' ),
-
將其修改成 apply 模式: func.apply( null, [ '張三', 19, '男'] )
-
-
方法模式: o.func( 123, 567 )
-
apply var o = { name: 'jim' };
-
foo.apply( o, [ 123, 567 ] ); 以 o 為上下文執行 apply
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
方法借用的案例
需求, 獲得 div 與 p 標簽, 並添加邊框 border: 1px solid red
一般做法:
-
var p_list = document.getElementsByTagName('p');
-
var div_list = document.getElementsByTagName('div');
-
-
var i = 0;
-
for( ; i < p_list.length; i++ ) {
-
p_list[ i ].style.border = "1px solid red";
-
}
-
for( i = 0; i < div_list.length; i++ ) {
-
div_list[ i ].style.border = "1px solid red";
-
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 利用方法借用優化,元素獲取
-
var t = document.getElementsByTagName;
-
var p_list = t.apply( document, [ 'p' ] ); // 方法借用
-
var div_list = t.apply( document, [ 'div' ] ); // 方法借用
- 1
- 2
- 3
-
接下來考慮下面的優化,兩個for循環,只要將數組合並了,就可以只用一個 for 循環
數組合並
-
var arr1 = [ 1, 2, 3 ];
-
var arr2 = [ 5, 6 ];
-
arr1.push.apply( arr1, arr2 ); // 方法調用,第一個給上對象
-
// 等價於 Array.prototype.push.apply( arr1, arr2 );
- 1
- 2
- 3
- 4
所以同理,利用 apply 方法借用,將兩個偽數組合並成同一個數組
-
var arr = []; // 偽數組沒有 push 方法,所以這里要 聲明一個 數組
-
arr.push.apply( arr, p_list ); // 將 p_list里的內容,一個個當成參數放了進來,相當於不用遍歷了
-
arr.push.apply( arr, div_list ); // 同上,方法借用
-
console.log( arr );
- 1
- 2
- 3
- 4
-
將兩者綜合, 使用forEach,最終 6 行就解決了
-
var t = document.getElementsByTagName, arr = [];
-
arr.push.apply( arr, t.apply( document, [ 'p' ] ) );
-
arr.push.apply( arr, t.apply( document, [ 'div'] ) );
-
arr.forEach( function( val, index, arr ) {
-
val.style.border = '1px solid red';
-
});
- 1
- 2
- 3
- 4
- 5
- 6
call 調用
在使用 apply 調用的時候, 函數參數, 必須以數組的形式存在. 但是有些時候數組封裝比較復雜
所以引入 call 調用, call 調用與 apply 完全相同, 唯一不同是 參數不需要使用數組
-
foo( 123, 567 );
-
-
foo.apply( null, [ 123, 567 ] );
-
-
foo.call( null, 123, 567 );
- 1
- 2
- 3
- 4
- 5
-
函數調用: 函數名.call( null, 參數1,參數2,參數3… );
-
方法調用: 函數名.call( obj, 參數1,參數2, 參數3… );
不傳參時,apply 和 call 完全一樣
借用構造方法實現繼承
-
function Person ( name, age, gender ) {
-
this.name = name;
-
this.age = age;
-
this.gender = gender;
-
}
-
-
function Student ( name, age, gender, course ) {
-
// 原型鏈結構不會變化,同時實現了繼承的效果
-
Person.call( this, name, age, gender );// 借用Person構造方法
-
this.course = course;
-
}
-
-
var p = new Student ( 'jim', 19, 'male', '前端' );
-
console.log( p );
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
補充知識 1. 函數的 bind 方法 ( ES5 )
bind 就是 綁定
還是上面那個案例 獲得 div 與 p 標簽, 並添加邊框 border: 1px solid red
-
var t = document.getElementsByTagName, arr = [];
-
arr.push.apply( arr, t.call( document, 'p' ) );
-
arr.push.apply( arr, t.call( document, 'div' ) );
-
arr.forEach( function( val, index, arr ) {
-
val.style.border = '1px solid red';
-
});
- 1
- 2
- 3
- 4
- 5
- 6
我們 讓 t 包含函數體(上面的方式),同時包含 對象,就可以更精簡
-
var t = document.getElementsByTagName.bind( document ), arr = [];
-
arr.push.apply( arr, t( 'p') );
-
arr.push.apply( arr, t( 'div') );
-
arr.forEach( function( val, index, arr ) {
-
val.style.border = '1px solid red';
-
});
- 1
- 2
- 3
- 4
- 5
- 6
bind : 就是讓函數綁定對象的一種用法
函數本身就是可以調用, 但是其如果想要作為方法調用, 就必須傳入宿主對象, 並且使用 call 或 apply 形式
但是 bind 使得我的函數可以與某一個對象綁定起來, 那么在調用函數的時候, 就好像是該對象在調用方法,就可以直接傳參,而不需要傳宿主對象。
語法: 函數.bind( 對象 )
返回一個函數 foo,那么調用 返回的函數 foo, 就好像 綁定的對象在調用 該方法一樣
-
t.call( document, 'p' );
-
-
t( 'p' ); 綁定后,就不用傳宿主對象了,這里調用時上下文已經變成了 document
-
-
bind 是 ES 5 給出的函數調用方法
- 1
- 2
- 3
- 4
- 5
補充知識 2. Object.prototype 的成員
Object.prototype 的成員
- constructor
- hasOwnProperty 判斷該屬性是否為自己提供
- propertyIsEnumerable 判斷屬性是否可以枚舉
- isPrototypeOf 判斷是否為原型對象
- toString, toLocaleString, valueOf
-
function Person() {
-
this.name = 'jim';
-
}
-
Person.prototype.age = 19;
-
var p = new Person();
-
console.log( p.hasOwnProperty( 'name' ) ); // true; p 是否含有 name 屬性,原型上不管
-
console.log( p.hasOwnProperty( 'age' ) ); // false; p 是否含有 age 屬性
-
-
/* Person.prototype 是 p 的原型 */
-
console.log( p.isPrototypeOf( Person.prototype ) ); // false
-
console.log( Person.prototype.isPrototypeOf( p ) ); // true;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
用途:一般把一個對象拷貝到另一個對象時,可以進行判斷,更加嚴謹,以防把原型中的屬性也拷貝過去了…
補充知識 3. 包裝類型
字符串 string 是基本類型, 理論上講不應該包含方法
那么 charAt, substr, slice, …等等方法,理論上都不應該有,但確是有的
所以引入包裝對象的概念,在 js 中為了更好的使用數據, 為三個基本類型提供了對應的對象類型
- Number
- String
- Boolean
在 開發中常常會使用基本數據類型, 但是基本數據類型沒有方法, 因此 js 引擎會在需要的時候自動的將基本類型轉換成對象類型, 就是包裝對象
-
“abc”.charAt( 1 )
-
“abc” -> s = new String( “abc” )
-
s.charAt( 1 ) 返回結果以后 s 就被銷毀
當基本類型.方法 的時候. 解釋器首先將基本類型轉換成對應的對象類型, 然后調用方法.
方法執行結束后, 這個對象就被立刻回收
在 apply 和 call 調用的時候, 也會有轉換發生. 上下文調用的第一個參數必須是對象. 如果傳遞的是數字就會自動轉換成對應的包裝類型
補充知識 4. getter 和 setter 的語法糖 ( ES5 )
語法糖: 為了方便開發而給出的語法結構
本身實現:
-
var o = (function () {
-
var num = 123;
-
return {
-
get_num: function () {
-
return num;
-
},
-
set_num: function ( v ) {
-
num = v;
-
}
-
};
-
})();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
-
希望獲得數據 以對象的形式
-
o.get_num(); => o.num 形式
-
-
希望設置數據 以對象的形式
-
o.set_num( 456 ); => o.num = 456 形式
- 1
- 2
- 3
- 4
- 5
所以 getter 和 setter 誕生 了
-
var o = (function () {
-
var num = 123;
-
return {
-
// get 名字 () { 邏輯體 }
-
get num () {
-
console.log( '執行 getter 讀寫器了' );
-
return num;
-
},
-
-
// set 名字 ( v ) { 邏輯體 }
-
set num ( v ) {
-
console.log( '執行 setter 讀寫器了' );
-
num = v;
-
}
-
};
-
})();
-
-
console.log( o.num ); // 執行 getter 讀寫器了 123
-
o.num = 33; // 執行 setter 讀寫器了
-
console.log( o.num ); // 執行 getter 讀寫器了 33
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
為什么不直接用 對象呢 var o = { num : 123 } ,也可以讀寫呀?
因為語法糖還可以 限制其賦值的范圍,使用起來特別爽
-
var o = (function () {
-
var num = 13;
-
return {
-
-
// get 名字 () { 邏輯體 }
-
get num () {
-
console.log( '執行 getter 讀寫器了' );
-
return num;
-
},
-
-
// set 名字 ( v ) { 邏輯體 }
-
set num ( v ) {
-
console.log( '執行 setter 讀寫器了' );
-
-
if ( v < 0 || v > 150 ) {
-
console.log( '賦值超出范圍, 不成功 ' );
-
return;
-
}
-
num = v;
-
}
-
};
-
})();
-
o.num = -1; // 執行 setter 讀寫器了
-
// 讀寫器賦值超出范圍, 不成功
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
補充知識 5. ES5 中引入的部分數組方法
- forEach
- map
- filter
- some
- every
- indexOf
- lastIndexOf
-
forEach, 數組遍歷調用,遍歷arr,參數三個 1某項, 2索引, 3整個數組
-
var arr = [ 'hello', ' js', { }, function () {} ];
-
// 遍歷 數組
-
arr.forEach( function ( v, i, ary ) {
-
console.log( i + '=====' + v );
-
console.log( ary );
-
});
- 1
- 2
- 3
- 4
- 5
- 6
-
-
map 映射
語法: 數組.map( fn )
返回一個數組, 數組的每一個元素就是 map 函數中的 fn 的返回值
就是對每一項都進行操作,並返回
-
var arr = [ 1, 2, 3, 4 ];
-
// 數學中: x -> x * x
-
var a = arr.map(function ( v, i ) {
-
return v * v;
-
});
-
// a [1, 4, 9, 16]
- 1
- 2
- 3
- 4
- 5
- 6
-
-
filter 就是篩選, 函數執行結果是 false 就棄掉, true 就收着
語法: 數組.filter( function ( v, i ) { return true/false })
-
var arr = [ 1, 2, 3, 4, 5, 6 ];
-
// 篩選奇數
-
var a = arr.filter( function ( v ) { return v % 2 === 1; });
-
// a [ 1, 3, 5 ]
- 1
- 2
- 3
- 4
-
-
some 判斷數組中至少有一個數據復合要求 就返回 true, 否則返回 false
-
var arr = [ '123', {}, function () {}, 123 ];
-
// 判斷數組中至少有一個數字
-
var isTrue = arr.some( function ( v ) { return typeof v === 'number'; } ); // true;
- 1
- 2
- 3
-
-
every 必須滿足所有元素都復合要求才會返回 true
-
var arr = [ 1, 2, 3, 4, 5, '6' ];
-
// 判斷數組中每一個都是數字
-
var isTrue = arr.every( function ( v ) { return typeof v === 'number'; } ); } ); // false;
- 1
- 2
- 3
-
-
indexOf 在數組中查找元素, 如果含有該元素, 返回元素的需要( 索引 ), 否則返回 -1
-
var arr = [ 1, 2, 3, 4, 5 ];
-
var res = arr.indexOf( 4 ); // 要找 4
-
console.log( res ); // 3 找 4 在 索引為 3 找到
-
-
var arr = [ 1, 2, 3, 4, 5, 4, 5, 6 ];
-
var res = arr.indexOf( 4, 4 ); // 要找 4, 從索引 4開始找
-
console.log( res ); // 找到了 索引為 5
- 1
- 2
- 3
- 4
- 5
- 6
- 7
-
-
lastIndexOf 從右往左找
-
var arr = [ 1, 2, 3, 4, 5, 4, 5, 6 ];
-
var res = arr.lastIndexOf( 4 );
-
console.log( res ); // 索引為 5, 從最后一項開始找,即從 length-1 項開始找
-
-