重读Javascript之Object

Object

对象是Javascript中最常的内置对象之一。除了null 和 undefined,其他的一切的都能够转换为对象。能够把对象算作含有键值一种数据结构,键称为对象的属性(只能是数字或许字符串),而值能够其他的任何范例。

例子

  • 对象是永久援用范例

//对象是永久援用范例,对象名指向内存中的某个位置,而不是复制值。
var studentA = {
    name: "sundway"
}
var studentB = studentA;
studentB.name = "modify";
console.log(studentA.name);        // "modify"
console.log(studentB.name);        // "modify"

/*studentA和studentB同时是对内存中的一个援用,所以studentB.name的变动是对studentB.name和studentA.name的配合变动*/
  • 对象的属性只能是字符串或许数字。

var studentA = {
    "name": "sundway" //“name”可写成name
}
var studentA = {
    1 : "sundway"
}
console.log(studentA[1]); // 输出"sundway"。
/*当属性为数字时,不能经由过程.运算符去读取属性值,只能经由过程[]去读取属性值。*/
  • Javascript一切的都能够表现的像对象,但只要null 和 undefined比较特别。

/*常常会有如许的误会,数字字面量不能看成对象运用。实在重要原因Javascript解析器将数字背面和.运算符当做浮点范例的字面量。*/
2.toString(); // Uncaught SyntaxError
2..toString(); // the second point is correctly recognized
2 .toString(); // note the space left to the dot
(2).toString(); // 2 is evaluated first

属性

属性形貌符:属性形貌符有两种重要情势,数据形貌符(configurable、enumerable、value、writable)和存取形貌(configurable、enumerable、get、set)符。数据形貌符是一个具有可写或不可写值的属性。存取形貌符是由一对 getter-setter 函数功能来形貌的属性。形貌符必需是两种情势之一;不能同时是二者。(注:polymer和vue等库底层貌似经由过程get和set完成双向绑定)

Object.prototype

Object.prototype是一个原型对象,在JavaScript中,一切的对象都是基于 Object;一切的对象都继续了Object.prototype的属性和要领,它们能够被掩盖(除了以null为原型的对象,如 Object.create(null));

Object.prototype.constructor

返回一个指向建立了该对象原型的函数援用。须要注重的是,该属性的值是谁人函数本身,而不是一个包含函数称号的字符串。

Object.prototype.__proto__

一个对象的proto 属性和本身的内部属性[[Prototype]]指向一个雷同的值 (一般称这个值为原型),原型的值能够是一个对象值也能够是null(比如说Object.prototype.proto的值就是null).该属性能够会激发一些毛病,因为用户能够会不知道该属性的特别性,而给它赋值,从而改变了这个对象的原型. 假如须要接见一个对象的原型,应当运用要领Object.getPrototypeOf.

要领

Object.create

ecma-262范例:

Object.create ( O [ , Properties ] )

The create function creates a new object with a specified prototype. When the create function is called, the following steps are taken:

  • If Type(O) is neither Object nor Null, throw a TypeError exception.

  • Let obj be ObjectCreate(O).

  • If the argument Properties is present and not undefined, then
    Return ObjectDefineProperties(obj, Properties).

  • Return obj.

Polyfill (基于Object.prototype.hasOwnProperty。)

if(typeof Object.create != 'function'){
    Object.create = (function(){
        //为了节约内存,运用一个同享的组织器
        function Temp() {};
        
        // 运用 Object.prototype.hasOwnProperty 更平安的援用 
        var hasOwn = Object.prototype.hasOwnProperty;
        
        return function (O) {
          // 1. 假如 O 不是 Object 或 null,抛出一个 TypeError 非常。
          if (typeof O != 'object') {
            throw TypeError('Object prototype may only be an Object or null');
          }

          // 2. 使建立的一个新的对象为 obj ,就和经由过程
          //    new Object() 表达式建立一个新对象一样,
          //    Object是规范内置的组织器名
          // 3. 设置 obj 的内部属性 [[Prototype]] 为 O。
          Temp.prototype = O;
          var obj = new Temp();
          Temp.prototype = null; // 不要坚持一个 O 的杂散援用(a stray reference)...

          // 4. 假如存在参数 Properties ,而不是 undefined ,
          //    那末就把参数的本身属性增加到 obj 上,就像挪用
          //    照顾obj ,Properties两个参数的规范内置函数
          //    Object.defineProperties() 一样。
          if (arguments.length > 1) {
            // Object.defineProperties does ToObject on its first argument.
            var Properties = Object(arguments[1]);
            for (var prop in Properties) {
              if (hasOwn.call(Properties, prop)) {
                obj[prop] = Properties[prop];
              }
            }
          }

          // 5. 返回 obj
          return obj;
        };
    })()
}

Object.is()

Object.is()[ES6]要领用来推断两个值是不是是同一个值。

ecma-262范例:

Object.is ( value1, value2 )
When the is function is called with arguments value1 and value2 the following steps are
taken:

  • Return SameValue(value1, value2).

以上范例中终究返回SameValue(x, y),而ecma-262范例中对SameValue(x, y)范例是:

SameValue(value1, value2)
The internal comparison abstract operation SameValue(x, y), where x and y are ECMAScript language values, produces true or false. Such a comparison is performed as follows:

  • ReturnIfAbrupt(x).

  • ReturnIfAbrupt(y).

  • If Type(x) is different from Type(y), return false.

  • If Type(x) is Undefined, return true.

  • If Type(x) is Null, return true.

  • If Type(x) is Number, then

    • If x is NaN and y is NaN, return true.

    • If x is +0 and y is −0, return false.

    • If x is −0 and y is +0, return false.

    • If x is the same Number value as y, return true.

    • Return false.

  • If Type(x) is String, then

    • If x and y are exactly the same sequence of code units (same length and same code units > at corresponding indices) return true; otherwise, return false.

  • If Type(x) is Boolean, then

    • If x and y are both true or both false, return true; otherwise, return false.

  • If Type(x) is Symbol, then

    • If x and y are both the same Symbol value, return true; otherwise, return false.

  • Return true if x and y are the same Object value. Otherwise, return false.

NOTE :This algorithm differs from the Strict Equality Comparison Algorithm (7.2.13) in its treatment of signed zeroes and NaNs.

上面提到这个算法和严厉比较算法(===)有所差别,我们能够标出几个差别的处所,然后在严厉比较算法(===)的基础上完成SameValue(value1, value2),同时也能够完成Object.is ( value1, value2 )。

Strict Equality Comparison

The comparison x === y, where x and y are values, produces true or false. Such a comparison > is performed as follows:

  • If Type(x) is different from Type(y), return false.

  • If Type(x) is Undefined, return true.

  • If Type(x) is Null, return true.

  • If Type(x) is Number, then

    • If x is NaN, return false.

    • If y is NaN, return false.

    • If x is the same Number value as y, return true.

    • If x is +0 and y is −0, return true.

    • If x is −0 and y is +0, return true.

    • Return false.

  • If Type(x) is String, then

    • If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices), return true.

    • Else, return false.
      If Type(x) is Boolean, then

    • If x and y are both true or both false, return true.

    • Else, return false.

  • If x and y are the same Symbol value, return true.

  • If x and y are the same Object value, return true.

  • Return false.

比较SameValue(value1, value2) 和 Strict Equality Comparison,Strict Equality Comparison不能辨别两个差别的数字 -0 和 +0,还会把两个 NaN 算作是不相等的。

Polyfill(基于===)

  Object.is = function(x, y) {
    // SameValue algorithm
    if (x === y) { // Steps 1-5, 7-10
      // Steps 6.b-6.e: +0 != -0
      return x !== 0 || 1 / x === 1 / y;
    } else {
      // Step 6.a: NaN == NaN
      return x !== x && y !== y;
    }
  };

Object.assign ( target, …sources )

Object.assign()[ES6] 要领能够把恣意多个的源对象所具有的本身可罗列属性拷贝给目的对象,然后返回目的对象。

Object.assign ( target, …sources )
The assign function is used to copy the values of all of the enumerable own properties from > one or more source objects to a target object. When the assign function is called, the >
following steps are taken:

  • Let to be ToObject(target).

  • ReturnIfAbrupt(to).

  • If only one argument was passed, return to.

  • Let sources be the List of argument values starting with the second argument.

  • For each element nextSource of sources, in ascending index order,

    • If nextSource is undefined or null, let keys be an empty List.

    • Else,

      • Let from be ToObject(nextSource).

      • Let keys be from.[[OwnPropertyKeys]]().

      • ReturnIfAbrupt(keys).

  • Repeat for each element nextKey of keys in List order,

    • Let desc be from.[GetOwnProperty].

    • ReturnIfAbrupt(desc).

    • if desc is not undefined and desc.[[Enumerable]] is true, then

      • Let propValue be Get(from, nextKey).

      • ReturnIfAbrupt(propValue).

      • Let status be Set(to, nextKey, propValue, true).

      • ReturnIfAbrupt(status).

  • Return to.

The length property of the assign method is 2.

Ployfill

因为 ES5 里压根就没有 symbol 这类数据范例,所以这个 polyfill 也没必要去支撑 symbol 属性(意义就是说,有 symbol 的环境一定有原生的 Object.assign):

if (!Object.assign) {
  Object.defineProperty(Object, "assign", {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target, firstSource) {
      "use strict";
      if (target === undefined || target === null)
        throw new TypeError("Cannot convert first argument to object");
      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) continue;
        var keysArray = Object.keys(Object(nextSource));
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) to[nextKey] = nextSource[nextKey];
        }
      }
      return to;
    }
  });
}

Demo

  • 拷贝 symbol 范例的属性

var o1 = { a: 1 };
var o2 = { [Symbol("foo")]: 2 };

var obj = Object.assign({}, o1, o2);
console.log(obj); // Object {a: 1, Symbol(foo): 2}
  • 继续属性和不可罗列属性是不能拷贝的

var obj = Object.create({foo: 1}, { // foo 是个继续属性。
    bar: {
        value: 2  // bar 是个不可罗列属性。
    },
    baz: {
        value: 3,
        enumerable: true  
    }
});
var copy = Object.assign({}, obj);
console.log(copy); //  Object {baz: 3}
  • 原始值会被隐式转换成其包装对象

var v1 = "123";
var v2 = true;
var v3 = 10;
var v4 = Symbol("foo")

var obj = Object.assign({}, v1, null, v2, undefined, v3, v4); 
// 源对象假如是原始值,会被自动转换成它们的包装对象,
// 而 null 和 undefined 这两种原始值会被完整疏忽。
// 注重,只要字符串的包装对象才有能够有本身可罗列属性。
console.log(obj); // { "0": "1", "1": "2", "2": "3" }
  • 拷贝属性过程当中发作非常

var target = Object.defineProperty({}, "foo", {
    value: 1,
    writeable: false
}); // target 的 foo 属性是个只读属性。

Object.assign(target, {bar: 2}, {foo2: 3, foo: 3, foo3: 3}, {baz: 4});
// TypeError: "foo" is read-only
// 注重这个非常是在拷贝第二个源对象的第二个属性时发作的。

console.log(target.bar);  // 2,申明第一个源对象拷贝胜利了。
console.log(target.foo2); // 3,申明第二个源对象的第一个属性也拷贝胜利了。
console.log(target.foo);  // 1,只读属性不能被掩盖,所以第二个源对象的第二个属性拷贝失利了。
console.log(target.foo3); // undefined,非常以后 assign 要领就退出了,第三个属性是不会被拷贝到的。
console.log(target.baz);  // undefined,第三个源对象更是不会被拷贝到的。

Object.keys(obj)

Object.keys() 要领会返回一个由给定对象的一切可罗列本身属性的属性名构成的数组,数组中属性名的分列递次和运用for-in轮回遍历该对象时返回的递次一致(二者的重要区别是 for-in 还会遍历出一个对象从其原型链上继续到的可罗列属性)。

Object.defineProperty(obj, prop, descriptor)

Object.defineProperty() 要领直接在一个对象上定义一个新属性,或许修正一个已存在的属性, 并返回这个对象。

Object.defineProperties(obj, props)

Object.defineProperties() 要领在一个对象上增加或修正一个或许多个自有属性,并返回该对象。

Object.freeze(obj)

Object.freeze() 要领能够凝结一个对象。也就是说,这个对象永久是不可变的.

Object.isFrozen(obj)

Object.isFrozen() 要领推断一个对象是不是被凝结(frozen)。ES5中范例和ES6有些差别:

If Type(O) is not Object throw a TypeError exception.(ES5)

If Type(O) is not Object, return true.(ES6)

所以Object.isFrozen(1);在ES5中会报错,而在ES6中会返回true.相似的另有Object.isExtensible()和Object.isSealed().

Object.preventExtensions(obj)

Object.preventExtensions() 要领让一个对象变的不可扩大,也就是永久不能再增加新的属性

Object.isExtensible(obj)

Object.isExtensible() 要领推断一个对象是不是是可扩大的(是不是能够在它上面增加新的属性)

Object.seal(obj)

bject.seal() 要领能够让一个对象密封,并返回被密封后的对象。密封对象是指那些不能增加新的属性,不能删除已有属性,以及不能修正已有属性的可罗列性、可设置性、可写性,但能够能够修正已有属性的值的对象。

Object.isSealed(obj)

Object.isSealed() 要领推断一个对象是不是是密封的(sealed)。(密封对象是指那些不可 扩大 的,且一切本身属性都不可设置的(non-configurable)对象。)

Object.getOwnPropertyDescriptor(obj, prop)

Object.getOwnPropertyDescriptor() 返回指定对象上一个自有属性对应的属性形貌符。(自有属性指的是直接给予该对象的属性,不须要从原型链上举行查找的属性)

Object.getOwnPropertyNames(obj)

Object.getOwnPropertyNames()要领返回一个由指定对象的一切本身属性的属性名(包含不可罗列属性)构成的数组。

Object.getOwnPropertySymbols(obj)

Object.getOwnPropertySymbols()[ES6] 要领会返回一个数组,该数组包含了指定对象本身的(非继续的)一切 symbol 属性键。

Object.getPrototypeOf(obj)

Object.getPrototypeOf()要领返回指定对象的原型。(也就是该对象内部属性[[prototype]]的值)

Object.observe(obj, callback)

Object.observe()[ES7] 要领用于异步的看管一个对象的修正。当对象属性被修正时,要领的回调函数会供应一个有序的修正流。Object.observe().该要领在两个月之前从发起中去掉了,能够运用第三方库替代。

Object.unobserve(obj, callback)

Object.unobserve()[ES7] 是用来移除经由过程 Object.observe()设置的观察者的要领。

Object.getNotifer(obj)

Object.getNotifer()[ES7]能够制造一个异步触发的对象。

Object.prototype.toString()

toString() 要领返回一个代表该对象的字符串。挪用该对象的toString()要领时会返回”[object type]”,这里的字符串type示意了一个对象范例。所以常常运用该要领去做范例推断,因为运用typeof,没法辨别array, null, function, object等。因为该要领会被子类要领掩盖,所以须要挪用Object.prototype的toString()。

var toString = Object.prototype.toString;

toString.call(new Function) // [object Function]
toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]

//Since JavaScript 1.8.5
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]

Object.prototype.toLocaleString();

toLocaleString() 要领返回一个该对象的字符串示意。该要领重要用于被本地化相干对象掩盖。

Object.prototype.hasOwnProperty()

hasOwnProperty() 要领用来推断某个对象是不是含有指定的本身属性

Object.prototype.isPrototypeOf(obj)

isPrototypeOf() 要领测试一个对象是不是存在于另一个对象的原型链上。

Object.prototype.propertyIsEnumerable(obj)

propertyIsEnumerable() 要领返回一个布尔值,表明指定的属性名是不是是当前对象可罗列本身属性.

Object.prototype.valueOf(obj)

Object.prototype.valueOf()要领返回特定对象的初始值。

    原文作者:sundway
    原文地址: https://segmentfault.com/a/1190000004224842
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞