若有使用過 JQuery,或許會對 extend 這個方法有些熟悉及基本了解。
先來看看 extend 的用法
jQuery.extend(obja, objb) 方法輸入為兩個參數,此方法會判斷 obja 與 objb 屬性,將 objb 物件所擁有的屬性覆寫/新增至 obja,並回傳 obja。
來看看程式碼比較快理解~
[javascript]
var a = {
‘name’: ‘John’ };
var b = {
‘name’: ‘Marry’,
‘phone’: 0912345678
};
var c = jQuery.extend(a, b);
console.log(a); // { ‘name’: ‘Marry’, ‘phone’: 0912345678 }
console.log(b); // { ‘name’: ‘Marry, ‘phone’: 0912345678 }
console.log(a === b); // false
console.log(a === c); // true
console.log(b === c); //false
[/javascript]
從上面的例子可以發現幾個值得注意的地方
- a 與 b 都存在的屬性,會被 b 覆寫
- a 與 c 是同一個物件
接下來,我們試著用 vanilla js 實作 extend 函式
[javascript] function extend(a, b) { for ( var prop in b ) { a[prop] = b[prop]; } return a; }
var a = {
‘name’: ‘John’ };
var b = {
‘name’: ‘Marry’,
‘phone’: 0912345678
};
var c = extend(a, b);
console.log(a); // { ‘name’: ‘Marry’, ‘phone’: 0912345678 }
console.log(b); // { ‘name’: ‘Marry, ‘phone’: 0912345678 }
console.log(a === b); // false
console.log(a === c); // true
console.log(b === c); //false [/javascript]
上面這段程式碼簡單實作了jQuery 基礎的 extend,但實際的 jquery.extend 提供更多的選項及參數彈性
舉例來說:
[code] function extend(a, b) { for ( var prop in b ) { a[prop] = b[prop]; } return a; } var a = { ‘second’: { ‘nest1’: 1 } }; var b = { ‘first’:1, ‘second’: { ‘nest2’: 2 } };
var c = extend(a, b); console.log(c); // {‘first’: 1, ‘second’: {‘nest2’:2}} [/code]
上面這段程式碼, a 與 b 物件皆有 second ,而且 second 底下的屬性是不相同的,但卻直接被覆寫。
也就是沒有 deep extend ( jquery.extend 中有一個 deep copy 的選項)
若是 deep copy 我們理論上會得到以下結果
[code] {‘first’: 1, ‘second’: {‘nest1’: 1, ‘nest2’:2}} [/code]
這部分使用 vanilla js 實作的程式碼就冗長了不少,完整程式碼附在下方
我想就不詳細解釋,大概提以下幾點
- 最重要的是利用遞迴的概念往下挖。(有學過 Tree 相關的資料結構應該懂XD)
- 第一個參數決定是否 deep,預設 false
- js function 內建的 arguments 去抓目前參數(因為第一個參數未必是 Object,可能是 deep)
[javascript]
function extend() { var extended = arguments[0]; var deep = false; var i = 0; var length = arguments.length;
if ( Object.prototype.toString.call( arguments[0] ) === ‘[object Boolean]’ ) { deep = arguments[0]; extended = arguments[1]; i++; } var merge = function (obj) { for ( var prop in obj ) { if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) { if ( deep && Object.prototype.toString.call(obj[prop]) === ‘[object Object]’ ) { extended[prop] = extend( true, extended[prop], obj[prop] ); } else { extended[prop] = obj[prop]; } } } }; for ( ; i < length; i++ ) { var obj = arguments[i]; merge(obj); } return extended; } [/javascript]
參考資料:
https://gomakethings.com/vanilla-javascript-version-of-jquery-extend/