簡體   English   中英

為什么 XMLHttpRequest 對象的屬性只能通過 console.log() 打印?

[英]Why properties of an XMLHttpRequest object are only printable through console.log()?

var obj = new XMLHttpRequest();
console.log("Object.keys():",Object.keys(obj));
console.log("Object.getOwnPropertyNames():",Object.getOwnPropertyNames(obj))
console.log("Object.entries():",Object.entries(obj))
console.log("JSON.stringify():",JSON.stringify(obj))

console.log("console.log:"); console.log(obj)

輸出:

Object.keys(): []
Object.getOwnPropertyNames(): []
Object.entries(): []
JSON.stringify():{}
控制台日志:
XMLHttpRequest {onreadystatechange: null, readyState: 0, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, ...}

如何在 javascript 中創建這樣一個對象,其屬性僅使用console.log(obj)打印,但不由上述任何函數返回?

我已經嘗試使用constructor function創建對象, object.create() (使用enumerable:false ), Object.assign() ,使用getters ,從類中初始化,從擴展類中初始化等

這與 WhatWG console.log規范有關

實現如何打印 args 取決於實現,但實現應該用空格或類似的東西分隔對象,因為這已成為開發人員的期望。

規范使輸出格式非常模糊,由實現決定打印什么。

您可以使用稱為 Symbol 的新數據類型為 JavaScript 對象創建鍵。

鏈接: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol

我附上了一個示例代碼,您可以在控制台中看到輸出。

 let nameSymbol = Symbol('name'); function Person (name) { this[nameSymbol] = name; } Person.prototype.toString = function toPersonString() { var symArr = Object.getOwnPropertySymbols(this); for (let sym of symArr) { this[sym.description] = this[sym]; delete this[sym]; } return this; } const dummyObject = new Person('random value'); console.log("Object.keys():",Object.keys(dummyObject)); // [] console.log("Object.getOwnPropertyNames():",Object.getOwnPropertyNames(dummyObject)) // [] console.log("Object.entries():",Object.entries(dummyObject)) // [] console.log("JSON.stringify():",JSON.stringify(dummyObject)) // {} console.log("console.log:", dummyObject.toString()); //  {name: "random value"}

XMLHttpRequest 實例上的所有屬性都是繼承的屬性,我的意思是它們不存在於實例本身,而是存在於其原型鏈上。

這解釋了為什么

const x = new XMLHttpRequest()
// all these methods consider only instance properties (owned properties) and thats why they return empty results
console.log(Object.keys(x)) // []
console.log(Object.getOwnPropertyNames(x)) // []
console.log(Object.entries(x)) // []
console.log(JSON.stringify(x)) // {}


// however if you try this you will get the results you want

console.log(Object.keys(x.__proto__)) // will not return symbol keys
console.log(Object.getOwnPropertyDescriptors(x.__proto__)) // will return descriptiors of every property whether its symbol or not

// you can see these results also by logging the xmlRequest, and looking at its __proto__ property in the console

// i will be calling the XMLHttpRequest instance for short as xmlRequest

您可以像這樣簡單地創建這樣一個對象

class A {}
A.prototype.someProperty = 10
const a = new A()
// again if you try these you will get results like the XMLHttpRequest instance
console.log(Object.keys(a)) // []
console.log(Object.getOwnPropertyNames(a)) // []
console.log(Object.entries(a)) // []
console.log(JSON.stringify(a)) // {}

但是,當您嘗試使用console.log(a)您不會像使用 xmlRequest 實例那樣看到someProperty ,這是意料之中的,因為它是一個繼承屬性。 您在記錄 xmlRequest 時看到這些屬性的原因是該對象正在接受特殊處理。

幸運的是,您可以使用chrome 自定義對象格式化程序重新創建這種特殊處理,為此您必須從 chrome 開發人員工具設置中啟用自定義格式化程序。

window.devtoolsFormatters = [{
    header: function(obj){
        if (!(obj instanceof A)){
         return null;
        }
        // to get the exact results like the xmlRequest, you need to remove quotes from the object keys in the json string, can be done with a regex
        return ["div",{}, JSON.stringify(obj.__proto__)]
    },
    hasBody: function(){
        return false;
    }
}]

class A {}
A.prototype.someProperty = 10

console.log(new A()) // {"someProperty":10}

如何在 javascript 中創建這樣一個對象,其屬性僅使用 console.log(obj) 打印,但不由上述任何函數返回?

我找到的一個接近的解決方案下面的一個。 這將使用console.log(obj)打印屬性。 然而 obj 是一個代理。

在 chrome 控制台上,結果與XMLHttpRequest輸出相同(類為Proxy )。 在 firefox 控制台上,它是Proxy類的表示,因此並不完全相同。


    const obj = new Proxy({prop1:"value1", prop2: "value2"}, {ownKeys: _=>[]});

    console.log("Object.keys():",Object.keys(obj));
    console.log("Object.getOwnPropertyNames():",Object.getOwnPropertyNames(obj))
    console.log("Object.entries():",Object.entries(obj))
    console.log("JSON.stringify():",JSON.stringify(obj))
    console.log(obj)

結果:

Object.keys(): []
Object.getOwnPropertyNames(): []
Object.entries(): []
JSON.stringify():{}
控制台日志:
代理 {prop1: "value1", prop2: "value2"}

console.log(obj.prop1) / obj.prop1="newValue"仍然有效。

Object.keys :只給出對象自己的可枚舉屬性。

Object.getOwnPropertyNames :提供直接在給定對象中找到的可枚舉和不可枚舉屬性。

Object.entries :給出對象自己的可枚舉字符串鍵控屬性對。

JSON.stringify :只考慮對象的可枚舉屬性。


創建您自己的此類對象

您可以使用Object.create來創建一個新對象,使用現有對象作為新創建對象的原型。

 obj1 = { key1: 'some key' }; var obj = Object.create(obj1); console.log("Object.keys():",Object.keys(obj)); console.log("Object.getOwnPropertyNames():",Object.getOwnPropertyNames(obj)) console.log("Object.entries():",Object.entries(obj)) console.log("JSON.stringify():",JSON.stringify(obj)) console.log("console.log:"); console.log(obj)

這是因為原型在 Javascript 中有效,這才是真正的原因。

當您從原型創建對象實例時,將不會顯示__proto__內的屬性(不可枚舉的屬性)

例如,嘗試:

function MyXMLHttpRequest(){};
MyXMLHttpRequest.prototype.name = "Edward"
var obj = new MyXMLHttpRequest();

console.log("Object.keys():",Object.keys(obj));
console.log("Object.getOwnPropertyNames():",Object.getOwnPropertyNames(obj))
console.log("Object.entries():",Object.entries(obj))
console.log("JSON.stringify():",JSON.stringify(obj))
console.log("console.log:"); console.log(obj)
console.log(obj.name)

你會看見:

控制台打印

為什么 XMLHttpRequest 對象的屬性只能通過 console.log() 打印?

這不是真的

var obj = new XMLHttpRequest();
for(var key in obj) console.log(key);

根據描述回答問題

如何在 javascript 中創建這樣的對象,其屬性僅使用打印

  var obj = Object.create({ foo: "foo", constructor: function() {} });

如果你想隱藏for in屬性for in你應該將enumerable屬性設置為false以獲得所需的屬性:

Object.defineProperty(obj, 'foo', {
  value: 42,
  enumerable: false
});

我認為這是最實用的方法。它會幫助你

class User {
  //this is a private field
  #name
  get Name() {
    return this.#name
  }
  set Name(val) {
    this.#name = val
  }
}

var obj = new User()
obj.Name = 'test'

console.log('Object.keys():', Object.keys(obj))
console.log('Object.getOwnPropertyNames():', Object.getOwnPropertyNames(obj))
console.log('Object.entries():', Object.entries(obj))
console.log('JSON.stringify():', JSON.stringify(obj))

console.log('console.log:')
console.log(obj)
console.log(obj.Name)

這是它的編譯代碼

function _classPrivateFieldSet(receiver, privateMap, value) {
  var descriptor = privateMap.get(receiver)
  if (!descriptor) {
    throw new TypeError('attempted to set private field on non-instance')
  }
  if (descriptor.set) {
    descriptor.set.call(receiver, value)
  } else {
    if (!descriptor.writable) {
      throw new TypeError('attempted to set read only private field')
    }
    descriptor.value = value
  }
  return value
}
function _classPrivateFieldGet(receiver, privateMap) {
  var descriptor = privateMap.get(receiver)
  if (!descriptor) {
    throw new TypeError('attempted to get private field on non-instance')
  }
  if (descriptor.get) {
    return descriptor.get.call(receiver)
  }
  return descriptor.value
} // Try edit message
class User {
  constructor() {
    _name.set(this, { writable: true, value: void 0 })
  }
  get Name() {
    return _classPrivateFieldGet(this, _name)
  }
  set Name(val) {
    _classPrivateFieldSet(this, _name, val)
  }
}
var _name = new WeakMap()
var obj = new User()
obj.Name = 'test'
console.log('Object.keys():', Object.keys(obj))
console.log('Object.getOwnPropertyNames():', Object.getOwnPropertyNames(obj))
console.log('Object.entries():', Object.entries(obj))
console.log('JSON.stringify():', JSON.stringify(obj))
console.log('console.log:')
console.log(obj)
console.log(obj.Name)

這是在鉻上編譯版本的結果在此處輸入圖片說明

這應該可以解決問題。

var obj = Object.create({
    get name(){
        return 'I go only to console.log()';
    }
});
console.log("Object.keys():",Object.keys(obj));
console.log("Object.getOwnPropertyNames():",Object.getOwnPropertyNames(obj));
console.log("Object.entries():",Object.entries(obj));
console.log("JSON.stringify():",JSON.stringify(obj));

console.log("console.log:", obj);

你可以這樣做:

Object.defineProperty(obj, 'key', {
    enumerable: false,
    value: '123'
});

具體來說, enumerable thingie 隱藏了屬性。

有關更多信息,請參閱此頁面: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

更新:

以下方法(上述方法的改進版本)似乎隱藏了所有提到的檢查的屬性,盡管它有點冗長:

var proto = {};
Object.defineProperty(proto, "key", {
    get: function () { return 123; }
});

var obj = Object.create(proto);

console.log(obj); // {}
console.log(Object.getOwnPropertyNames(obj)); // []
console.log(obj.key); // 123

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM