標籤:
一、繼承機制
1、對象冒充:建構函式使用 this 關鍵字給所有屬性和方法賦值,可使 ClassA 建構函式成為 ClassB 的方法,然後調用它。
function ClassZ() { this.newMethod = ClassX; this.newMethod(); delete this.newMethod; this.newMethod = ClassY; this.newMethod(); delete this.newMethod;}
這裡存在一個弊端,如果存在兩個類 ClassX 和 ClassY 具有同名的屬性或方法,ClassY 具有高優先順序。因為它從後面的類繼承。除這點小問題之外,用對象冒充實現多重繼承機制輕而易舉。
2、apply()、 call() 方法是與經典的對象冒充方法最相似
function ClassB(sColor, sName) { //this.newMethod = ClassA; //this.newMethod(color); //delete this.newMethod; ClassA.call(this, sColor); this.name = sName; this.sayName = function () { alert(this.name); };}
3、原型鏈
function ClassA() { } ClassA.prototype.color = "blue"; ClassA.prototype.sayColor = function () { alert(this.color); }; function ClassB() { } ClassB.prototype = new ClassA();
把 ClassB 的 prototype 屬性設定成 ClassA 的執行個體注意:調用 ClassA 的建構函式,沒有給它傳遞參數。這在原型鏈中是標準做法。要確保建構函式沒有任何參數。二、call & applyapply:方法能劫持另外一個對象的方法,繼承另外一個對象的屬性.Function.apply(obj,args)方法能接收兩個參數 call:和apply的意思一樣,只不過是參數列表不一樣. Function.call(obj,[param1[,param2[,…[,paramN]]]])
對象的繼承,一般的做法是複製:Object.extend
Object.extend = function(destination, source) { for (property in source) { destination[property] = source[property]; } return destination; }
除此之外,還有種方法,就是:Function.apply或者Function.call。 通過 call() 或 apply() 方法可以設定 this 的值, 且作為已存在對象的新方法調用。
在 JavaScript strict 模式(strict mode)下, 在調用函數時第一個參數會成為 this 的值, 即使該參數不是一個對象。在 JavaScript 非strict 模式(non-strict mode)下, 如果第一個參數的值是 null 或 undefined, 它將使用全域對象替代。
使用情境:
1、 arguments 轉換為數組
// 返回的是數組,但是arguments本身保持不變vararg=[].slice.call(arguments);//[].slice.call(document.getElementsByTagName(‘li‘));
2、借用
var foo = { name: ‘joker‘, showName: function() { console.log(this.name); } } var bar = { name: ‘rose‘ } foo.showName.call(bar);
3、繼承
var Student = function(name, age, high) { // use call Person.call(this,name,age); this.high=high;}
Person.apply(this,arguments);
this:在建立對象在這個時候代表的是student
arguments:是一個數組,也就是[“qian”,”21”,”一年級”];
用student去執行Person這個類裡面的內容,在Person這個類裡面存在this.name等之類的語句,這樣就將屬性建立到了student對象裡面
在給對象參數的情況下,如果參數的形式是數組的時候,比如apply樣本裡面傳遞了參數arguments,這個參數是數群組類型,並且在調用Person的時候參數的列表是對應一致的(也就是Person和Student的參數列表前兩位是一致的) 就可以採用 apply , 如果我的Person的參數列表是這樣的(age,name),而Student的參數列表是(name,age,grade),這樣就可以用call來實現了,也就是直接指定參數列表對應值的位置(Person.call(this,age,name,grade));
4、 封裝對象時保證this的指向
var _this = this; _this.$box.on(‘mousedown‘, function() { return _this.fndown.call(_this); })
5、代碼最佳化
返回數組最大值
alert(Math.max(5,8)) //8alert(Math.max(5,7,9,3,1,6)) //9alert(Math.max([5,7,9,1])) // 找出數組中最大的元素,這樣卻是不行的。function getMax(arr){ var arrLen=arr.length; for(var i=0,ret=arr[0];i<arrLen;i++){ ret=Math.max(ret,arr[i]); } return ret;}//這樣寫麻煩而且低效。如果用 apply呢function getMax2(arr){ return Math.max.apply(null,arr);}
兩段代碼達到了同樣的目的,但是getMax2卻優雅,高效,簡潔得多。apply會將一個數組裝換為一個參數接一個參數的傳遞給方法。這塊在調用的時候第一個參數給了一個null,這個是因為沒有對象去調用這個方法,我只需要用這個方法幫我運算,得到返回的結果就行,.所以直接傳遞了一個null過去 。
//兩個數組拼接,要把 arr2展開,然後一個一個追加到arr1中去var arr1=[1,3,4];var arr2=[3,4,5];arr1.push(arr2)//[1,3,4,[3,4,5]]顯然不行//只能用一個迴圈去一個一個的push(當然也可以用arr1.concat(arr2),但是concat方法並不改變arr1本身)var arrLen=arr2.lengthfor(var i=0;i<arrLen;i++){ arr1.push(arr2[i]);}//使用apply,arr1執行push方法,arr2作為參數傳入。arr1調用了push方法,參數是通過apply將數組裝換為參數列表的集合Array.prototype.push.apply(arr1,arr2)
call 和 apply 都是為了改變某個函數運行時的 context 即上下文而存在的,換句話說,就是為了改變函數體內部 this 的指向。因為 JavaScript 的函數存在「定義時上下文」和「運行時上下文」以及「上下文是可以改變的」這樣的概念。
二者的作用完全一樣,只是接受參數的方式不太一樣
function add(a, b){console.dir(this);}function sub(a, b){console.dir(this);}add(1,2); //"Window"sub(1,2); //"Window"add.call(sub, 1, 2); //"sub(a, b)"sub.apply(add, [1, 2]); //"add(a, b)"
javascript繼承機制 & call apply使用說明