特徵: 簡單的函數調用, 函數名前面沒有任何引導內容數組
function foo(){} var fn = function(){}; ... foo(); fn(); (function(){})(); // 上面的三種都是簡單的函數調用
this的含義瀏覽器
特徵: 方法必定是依附於一個對象, 將函數賦值給對象的一個屬性, 那麼就成爲方法.就是函數前面必須有引導對象app
function foo(){ this.method = function(){}; } var o = { method : function(){} }
this的含義函數
注意點
在 arguments 這種僞數組, 或者 [] 數組這樣的對象中, 這樣調用函數也是方法調用, this 會只指向對象this
分析:
因爲構造函數只是給 this 添加成員, 而方法也能夠完成這個操做,對與 this 來講, 構造函數和方法沒有本質區別prototype
普通狀況, 能夠理解爲構造函數已經默認進行了 return this, 添加在後面的都不會執行code
特殊狀況, return 對象, 最終返回對象對象
,
進行隔離不管是 call 仍是 apply 在沒有後面參數的狀況下(函數無參數, 方法無參數), 二者一致繼承
function foo(){ console.log(this); // this => window } var obj = {}; foo.apply( obj ); // this => obj foo.call( obj ); // this => obj
foo(); foo.apply(); foo.apply(null); foo.apply(undefined); foo.call(); foo.call(null); foo.call(undefined); // 上面都this都指向window
再使用上下文調用的時候, 原函數(方法)可能會帶有參數, 那麼要讓這些參數在上下文中調用, 就須要這個第二, ( n )個參數來表示事件
function foo(num){ console.log(num); } foo.apply(null, [123]); // 至關於 foo(123);
上下文調用只是修改this, 可是使用最多的地方是借用函數調用
var a = {}; a[0] = 'a'; a[1] = 'b'; a.length = 2; // 使用數組自帶方法 concat(); // 不修改原數組 var arr = []; var newArr = arr.concat(a);
分析
因爲 a 是僞數組, 並非真正的數組, 不能使用數組的方法, concat 會將 a 做爲一個總體 Object 加入數組
apply 方法有一個特性, 能夠將數組或者僞數組做爲參數
foo.apply( obj, 僞數組 ); // IE8 不支持
將 a 做爲 apply 的第二個參數
var arr = []; var newArr = Array.prototype.concat.apply( arr, a);
由上面的數組轉換, 咱們能夠獲得結論, 應該涉及到數組操做的方法理論上都應該能夠
push, pop, unshift, shift
slice
splice
var a = {length : 0}; // 設置僞數組的長度 a[ a.length++ ] = 'a'; a[ a.length++ ] = 'b'; // 在給僞數組的元素賦值時, 同時修改僞數組的 length 屬性 // a[0] = 'a'; a.length++;
var arr = []; arr.push.apply( arr, a ); // 利用 apply 能夠處理僞數組的特性, 進行傳參 // 至關於 arr.push(a[0], a[1])
slice 方法不會修改原數組
經過 apply 實現僞數組使用 slice 方法
var a = { length : 0 }; a[a.length++] = 'a'; a[a.length++] = 'b'; var arr =[]; var newArr = arr.slice.apply(a ,[0])
傳統方法
var arr = [1,2,3,4,5,6,7,8,9]; var max = arr[0]; for(var i = 0;i < arr.length;i++){ if(max < arr[i]){ max = arr[i] } }
使用 apply 借用 Math.max 獲取數組中最大值
利用 apply 能夠傳入參數能夠是數組或是僞數組的特性
var arr = [1,2,3,4,5,6,7,8,9]; Math.max.apply(null, arr);
瞭解了四種函數調用模式, 咱們能夠深一步瞭解建立對象的幾種方式, 對象是經過構造函數建立的
document.createElement()
function createPerson(name, age, gender){ var o = {}; o.name = name; o.age = age; o.gender = gender; return o; }
function Person(name,age,gender){ this.name = name; this.age = age; this.gender = gender; }
function createPerson(name,age,gender){ var o = {}; o.name = name; o.age = age; o.gender = gender; return o; } var p = new createPerson('Bob',19,'male')
function createPerson(name,age,gender){ this.name = name; this.age = age; this.gender = gender; } createPerson.prototype = { constructor : createPerson, wife : '高圓圓' }
function Person(name,age,gender){ this.name = name; this.age = age; this.gender = gender; } function Studner(name,age,gender,course){ // 借用構造函數Person, 建立 Student 對象 Person.call(this,name,age,gender); this.course = course; } var boy = new Student('Bob',19,'male',;Math);
// 臨時中轉 function person(o){ function Foo(){}; F.prototype = o; return new F(); } // 寄生函數 function create(o){ var fn = person(o); fn.move = function(){}; fn.eat = function(){}; fn.sleep = function(){}; return fn; } var boy = { name : 'Bob', age : 19, famliy : ['father','mother','wife'] } var boy1 = create(boy); console.log(boy1.name); console.log(boy1.family); // 此時 boy1 有了 boy 的成員
例題 1
function Foo(){ getName = function(){ alert(1); }; return this; } function getName(){ alert(5); } Foo.getName = function(){ alert(2); }; Foo.prototype.getName = function(){ alert(3); }; getName = function(){ alert(4); }; Foo.getName(); // 2 getName(); // 4 Foo().getName(); // 4 1 getName(); // 4 1 new Foo.getName(); // 2 new Foo().getName(); // 3 new new Foo().getName(); // 3
分析
例題 2
var length = 10; function fn() { console.log( this.length ); } var obj = { length: 5, method: function ( fn ) { fn(); arguments[ 0 ](); // [ fn, 1, 2, 3, length: 4] } }; obj.method( fn, 1, 2, 3 );
分析
例題 3
var o = { method : function(){ console.log(this); } }; o.method(); var f = o.method; f(); (o.method)(); var obj = {}; (obj.fn = o.method)(); (obj.fn)();
分析