lodash 中文學習拾零之 Object篇
4. 處理哪些Object?
lodash的Object方法處理的是:function, array, string, JSON
4.1 判斷Object型別
lodash提供了一系列用於判斷Obejct型別的方法,稱為 variadic functions:
_.isString
_.isArray
_.isTypedArray
_.isNumber
_.isBoolean
_.isDate
_.isPlainObject
_.isRegExp
_.isFunction
_.isObject
_.isPlainObject
_.isFinite
_.isElement
_.isNative
_.isUndefined
_.isNull
_.isNaN
//例如下面這個 _.isString用來判斷輸入的引數是否是String型別
function hello(name) {
if (_.isString(name)) {
return 'hello, ' + name;
}
}
hello('world');
// → "hello, world"
hello();
// → undefined
//判斷是否是函式的引數
_.isArguments(function() { return arguments; }());
// → true
_.isArguments([1 , 2, 3]);
// → false
//判斷是否語言意義上的Object:
//(e.g. arrays, functions, objects, regexes, new Number(0), and new String(''))
_.isObject({});
// → true
_.isObject([1, 2, 3]);
// → true
_.isObject(1);
// → false
//判斷是否 plain object
function Foo() {
this.a = 1;
}
_.isPlainObject(new Foo);
// → false
_.isPlainObject({a:1 });
// → true
4.2 賦值與取值(Assigning and accessing properties)
建立一個javascript object物件並對之賦值是個常見工作,其中有些過程挺無聊的,比如:把一個物件的部分資料搞到另一個裡去、或者必須確保為新物件填充預設值、確定是否存在某個key並且準確的賦值……
不用慌,對於上述等等無聊的事情,lodash提供了一系列工具來讓你輕鬆完成。
4.2.1 擴充套件物件(Extending objects)
4.2.1.1 _.assign(object, [sources], [customizer], [thisArg])
注意[sources]這個引數,理論上可以是無限多,預設情況下,後面的同名Key:Value對會覆蓋前面的值。
的返回值一定是個Object
var object = {
name: '湯姆',
age: 42
};
_.assign(object, {occupation: '程式猿'},{'name':'傑瑞'});
//注意,此處新的 name:'傑瑞' 覆蓋了原有的資料 '湯姆'
// →
// {
// name: "傑瑞",
// age: 42,
// occupation: "程式猿"
// }
// 設計自定義的回撥函式
var defaults = _.partialRight(_.assign, function(value, other) {
return _.isUndefined(value) ? other : value;
});
defaults(object, { 'language': 'JS' }, { 'name': '果菲' });
// 原來沒有的屬性language及其值被添加了上去,而'name'的值還是保持不變
// → {
// 'name': '傑瑞',
// 'age': 42,
// 'occupation':'程式猿',
// 'language':'JS'
// }
4.2.1.2 _.merge(object, [sources], [customizer], [thisArg])
採用遞迴的方式將sources objects合併到目標Object當中,後面的相同屬性會覆蓋前面的相同屬性。
_.merge (合併器)的
第一個引數是目標Object
第二個引數是源Object(即要合併進來的內容)
第三個引數是自定義處理器並接受五個引數(objectValue, sourceValue, key, object, source)
.merge的返回值一定是個Object
var users = {
'data': [{ 'user': '錢夫人' }, { 'user': '阿土伯' }]
};
var ages = {
'data': [{ 'age': 36 }, { 'age': 50 }]
};
_.merge(users, ages);
// → { 'data':
// [
// { 'user': '錢夫人', 'age': 36 },
// { 'user': '阿土伯', 'age': 50 }
// ]
// }
var object1 = {
states: { running: 'poweroff' },
names: [ 'CentOS', 'REHL' ]
},
object2 = {
states: { off: 'poweron' },
names: [ 'Ubuntu', 'Debian' ]
};
_.merge(object1, object2, function(a, b) {
if (_.isArray(a)) {
return a.concat(b);
}
});
// →
// {
// states: {
// running: "poweroff",
// off: "poweron"
// },
// names: [
// "CentOS",
// "REHL",
// "Ubuntu",
// "Debian"
// ]
// }
//注意下面的例子的差別:
_.merge({a:[20,30]},[1,2]);
//{"0":1,"1":2,"a":[20,30]}
_.merge([1,2],{a:[20,30]});
//[1,2]
擴充套件物件小結
.merge 與 .assign 的相似之處在於:都是把source object資料加到目標object中;
不同之處在於.assign 會直接將source object的property覆蓋目標object,不會考慮差異; 而.merge則會比較兩者的property細節,已存在的會被覆蓋,新的則會新增上去。
4.2.2 預設值
用於設定object預設值
4.2.2.1 _.defaults(object, [sources])
目標Object中設定的值是預設值,不能被sources的相同property覆蓋
_.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
// → { 'user': 'barney', 'age': 36 }
_defaults([1,2],[3,4,5]);
// → [1,2,5]
4.2.2.2 _.defaultsDeep(object, [sources])
與defaults類似,但是用遞迴的方式分配預設值
_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }
4.3 查詢keys和values
4.3.1_.findKey(object, [predicate=_.identity], [thisArg])
有點型別於Collection方法裡的_.find,但是返回的是被匹配的Key的值(string|undefined)
var users = {
'barney': { 'age': 36, 'active': true },
'fred': { 'age': 40, 'active': false },
'pebbles': { 'age': 1, 'active': true }
};
_.findKey(users, function(chr) {
return chr.age < 40;
});
// → 'barney' (iteration order is not guaranteed)
// using the `_.matches` callback shorthand
_.findKey(users, { 'age': 1, 'active': true });
// → 'pebbles'
// using the `_.matchesProperty` callback shorthand
_.findKey(users, 'active', false);
// → 'fred'
// using the `_.property` callback shorthand
_.findKey(users, 'active');
// → 'barney' 注意這個值和上一個值的區別
//使用迭代器處理複雜查詢的例子:
var object = {
Maria: [
'Python',
'Lisp',
'Go'
],
Douglas: [
'CSS',
'Clojure',
'Haskell'
]
};
var lang = 'Lisp';
//通過迭代器檢查資料型別
_.findKey(object, function(value) {
if (_.isArray(value)) {
return _.contains(value, lang);
} else {
return value === lang;
} });
// → "Maria"
4.3.2_.findLastKey(object, [predicate=_.identity], [thisArg])
_.findLastKey查詢的是最後一個符合條件的key
var users = {
'barney': { 'age': 36, 'active': true },
'fred': { 'age': 40, 'active': false },
'pebbles': { 'age': 1, 'active': true }
};
_.findLastKey(users, function(chr) {
return chr.age < 40;
});
// → returns `pebbles` 對比一下前面的例子 `_.findKey` 返回的是 `barney`
4.4 遍歷物件(Iterating over objects)
4.4.1 基礎遍歷(Basic For Each)
4.4.1.1_.forOwn(object, [iteratee=_.identity], [thisArg])
實際上,當遍歷的物件都是一個Object時,forOwn與Collection方法中的forEach的作用是完全相同的,因為它們都有共同的 base function
var object = {
name: 'Vince',
age: 42,
occupation: 'Architect'
}, result = [];
_.forOwn(object, function(value, key) {
result.push(key + ': ' + value);
});
// →
// [
// "name: Vince",
// "age: 42",
// "occupation: Architect"
// ]
function Foo() {
this.a = 1;
this.b = 2;
}
//下面的例子說明:(1)function也是object;(2)prototype不是"Own Key"
function Foo() {
this.a = 1;
this.b = 2;
}
Foo.prototype.c = 3;
_.forOwn(new Foo, function(value, key) {
console.log(key);
});
// → logs 'a' and 'b' (iteration order is not guaranteed)
4.4.1.2_.forOwnRight(object, [iteratee=_.identity], [thisArg])
遍歷方向與forOwn相反。
4.4.2 搜尋繼承屬性 Including inherited properties
_.forOwn無法檢索繼承下來的屬性,所以要檢索繼承的屬性就要用 forIn和 forInRight了。
4.4.2.1_.forIn(object, [iteratee=_.identity], [thisArg])
function Foo() {
this.a = 1;
this.b = 2;
}
Foo.prototype.c = 3;
_.forIn(new Foo, function(value, key) {
console.log(key);
});
// → logs 'a', 'b', and 'c'
4.4.2.2_.forInRight(object, [iteratee=_.identity], [thisArg])
與_.forIn的次序相反
4.5 Keys和Values
4.5.1 Keys
4.5.1.1 _.keys(object)
獲得object的所有own key,返回值為陣列
function Foo() {
this.a = 1;
this.b = 2;
}
Foo.prototype.c = 3;
_.keys(new Foo);
// → ['a', 'b'] (prototype.c 沒有被包含在內)
_.keys('hi');
// → ['0', '1'] (string被當成陣列,0和1就是'h'和'i'的key)
4.5.1.2 _.keysIn(object)
獲得object的所有key,prototype也包含在內
4.5.2 Values
4.5.2.1 _.values(object)
獲得Object所有的own key的值
function Foo() {
this.a = 1;
this.b = 2;
}
Foo.prototype.c = 3;
_.values(new Foo);
// → [1, 2]
_.values('hi');
// → ['h', 'i']
4.5.2.2 _.valuesIn(object)
獲得Object所有Key的值,prototype的值也包括在內。
function Foo() {
this.a = 1;
this.b = 2;
}
Foo.prototype.c = 3;
_.valuesIn(new Foo);
// → [1, 2, 3] (iteration order is not guaranteed)
4.6 呼叫方法
4.6.1_.result(object, path, [defaultValue])
第一個引數是Object,第二個引數是被呼叫的方法(或屬性)的路徑,第三個引數是預設值
var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
_.result(object, 'a[0].b.c1');
// → 3
_.result(object, 'a[0].b.c2');
// → 4
_.result(object, 'a.b.c', 'default');
// → 'default'
_.result(object, 'a.b.c', _.constant('default'));
// → 'default'
4.6.2 _.functions(object)
列出object的所有方法
function Person(first, last) {
this.first = first;
this.last = last;
}
Person.prototype.name = function() {
return this.first + ' ' + this.last;
};
_.functions(new Person('Teresa', 'Collins'));
// → [ "name" ]
4.7 轉化物件(Transforming objects)
有時候,我們手上的物件並不能滿足我們的需要,而要轉成其他形式的資料結構,而lodash剛好提供了一批這樣的工具。
4.7.1 _.pairs(object)
將物件轉為陣列
_.pairs({ 'barney': 36, 'fred': 40 });
// → [['barney', 36], ['fred', 40]]
4.7.2 _.pick(object, [predicate], [thisArg])
挑選物件的特定的property,並返回一個新的object
var object1 = {
name: 'Kevin Moore',
occupation: 'Programmer'
},
object2 = {
specialty: 'Python',
employer: 'Acme'
};
_.assign(object1, _.pick(object2, 'specialty'));
// →
// {
// name: "Kevin Moore",
// occupation: "Programmer",
// specialty: "Python"
// }
4.7.3 _.omit(object, [predicate], [thisArg])
扔掉指定的property,返回一個新的Object
var object1 = {
name: 'Kevin Moore',
occupation: 'Programmer'
},
object2 = {
specialty: 'Python',
employer: 'Acme'
};
_.assign(object1, _.omit(object2, 'employer'));
// →
// {
// name: "Kevin Moore",
// occupation: "Programmer",
// specialty: "Python"
// }
var object = { 'user': 'fred', 'age': 40 };
_.omit(object, 'age');
// → { 'user': 'fred' }
_.omit(object, _.isNumber);
// → { 'user': 'fred' }
4.7.4 _.invert(object, [multiValue])
顛倒key和value,第二個引數為是否接受多個值
var object = { 'a': 1, 'b': 2, 'c': 1 };
_.invert(object);
// → { '1': 'c', '2': 'b' }
// with `multiValue`
_.invert(object, true);
// → { '1': ['a', 'c'], '2': ['b'] }
4.8 建立和克隆物件
4.8.1_.create(prototype, [properties])
建立物件
function Shape() {
this.x = 0;
this.y = 0;
}
function Circle() {
Shape.call(this);
}
Circle.prototype = _.create(Shape.prototype, {
'constructor': Circle
});
var circle = new Circle;
circle instanceof Circle;
// → true
circle instanceof Shape;
// → true
4.8.2 _.clone(value, [isDeep], [customizer], [thisArg])
克隆物件
function Person(first, last) {
this.first = first;
this.last = last;
}
var object1 = {
first: 'Laura',
last: 'Gray'
},
object2 = new Person('Bruce', 'Price'),
clone1 = _.clone(object1),
clone2 = _.clone(object2);
clone1.first === 'Laura';
// → true
clone2.first === 'Bruce' && clone2 instanceof Person;
// → false
4.8.3 _.cloneDeep(value, [customizer], [thisArg])
深度克隆
var users = [
{ 'user': 'barney' },
{ 'user': 'fred' }
];
var deep = _.cloneDeep(users);
deep[0] === users[0];
// → false
// using a customizer callback
var el = _.cloneDeep(document.body, function(value) {
if (_.isElement(value)) {
return value.cloneNode(true);
}
});
el === document.body
// → false
el.nodeName
// → BODY
el.childNodes.length;
// → 20