1. 程式人生 > >lodash 中文學習拾零之 Object篇

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;
}
//下面的例子說明:(1function也是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被當成陣列,01就是'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