Có thể ghi đè hàm toString () của JavaScript để cung cấp đầu ra có ý nghĩa cho việc gỡ lỗi không?


115

Khi tôi console.log()là một đối tượng trong chương trình JavaScript của mình, tôi chỉ thấy đầu ra [object Object], điều này không hữu ích lắm trong việc tìm ra đối tượng (hoặc thậm chí là loại đối tượng) đó là gì.

Trong C #, tôi đã quen với việc ghi đè ToString()để có thể tùy chỉnh biểu diễn trình gỡ lỗi của một đối tượng. Có điều gì tương tự mà tôi có thể làm trong JavaScript không?


2
Tôi thấy rằng kết quả đầu ra là cách đáng tin cậy nhất để cho bạn biết một biến chứa những gì (hoặc ít nhất là tốt hơn typeof).
alex

Câu trả lời:


103

Bạn cũng có thể ghi đè toStringtrong Javascript. Xem ví dụ:

function Foo() {}

// toString override added to prototype of Foo class
Foo.prototype.toString = function() {
  return "[object Foo]";
}

var f = new Foo();
console.log("" + f); // console displays [object Foo]

Xem thảo luận này về cách xác định tên loại đối tượng trong JavaScript.


8
Mặc dù đúng, hàm cảnh báo sẽ hiển thị giá trị trả về của hàm ghi đè thuộc tính nguyên mẫu toString, Object.prototype.toString.call(f)vẫn sẽ hiển thị [object Object].
Frederik Krautwald

14
'Object.prototype.toString.call (f) sẽ vẫn hiển thị [đối tượng Đối tượng].' Vâng, vì đó là một chức năng hoàn toàn khác với 'Foo.prototype.toString', lol.
Triynko

5
Trong trường hợp ai đó giống như tôi kết thúc ở đây, bạn có thể sử dụng Sybmol.toStringTag trong ES6 để tùy chỉnh hành vi của Object.prototype.toString.call. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
TLadd

32

Ghi đè đầu tiên toStringcho đối tượng của bạn hoặc nguyên mẫu:

var Foo = function(){};
Foo.prototype.toString = function(){return 'Pity the Foo';};

var foo = new Foo();

Sau đó chuyển đổi thành chuỗi để xem biểu diễn chuỗi của đối tượng:

//using JS implicit type conversion
console.log('' + foo);

Nếu bạn không thích nhập thêm, bạn có thể tạo một hàm ghi các biểu diễn chuỗi của các đối số của nó vào bảng điều khiển:

var puts = function(){
    var strings = Array.prototype.map.call(arguments, function(obj){
        return '' + obj;
    });
    console.log.apply(console, strings);
};

Sử dụng:

puts(foo)  //logs 'Pity the Foo'

puts(foo, [1,2,3], {a: 2}) //logs 'Pity the Foo 1,2,3 [object Object]'

Cập nhật

E2015 cung cấp cú pháp đẹp hơn nhiều cho nội dung này, nhưng bạn sẽ phải sử dụng trình chuyển tiếp như Babel :

// override `toString`
class Foo {
  toString(){
    return 'Pity the Foo';
  }
}

const foo = new Foo();

// utility function for printing objects using their `toString` methods
const puts = (...any) => console.log(...any.map(String));

puts(foo); // logs 'Pity the Foo'

6
console.log ('' + foo); đây là vấn đề tôi không thấy bất kỳ triển khai toString nào cho đến khi tôi đạt được câu trả lời của bạn.
ahmadalibaloch

13

Một cách dễ dàng để có được đầu ra có thể gỡ lỗi trong trình duyệt JS là chỉ cần tuần tự hóa đối tượng thành JSON. Vì vậy, bạn có thể thực hiện một cuộc gọi như

console.log ("Blah: " + JSON.stringify(object));

Vì vậy, ví dụ, alert("Blah! " + JSON.stringify({key: "value"}));tạo ra một cảnh báo với văn bảnBlah! {"key":"value"}


Điều đó khá tiện dụng. Đầu ra có thể hơi lớn như tôi tưởng tượng, nhưng hoạt động rất khó khăn!
defos1

@dev Tiện dụng, nhưng không ghi đè toString ().
Dan Dascalescu

10

Nếu bạn đang sử dụng Node, nó có thể đáng xem xét util.inspect.

var util = require('util')

const Point = {
  x: 1,
  y: 2,
  [util.inspect.custom]: function(depth) { return `{ #Point ${this.x},${this.y} }` }

}

console.log( Point );

Điều này sẽ mang lại:

{ #Point 1,2 }

Trong khi phiên bản không có bản in kiểm tra:

{ x: 1, y: 2 }

6

Chỉ cần ghi đè toString()phương thức.

Ví dụ đơn giản:

var x = {foo: 1, bar: true, baz: 'quux'};
x.toString(); // returns "[object Object]"
x.toString = function () {
    var s = [];
    for (var k in this) {
        if (this.hasOwnProperty(k)) s.push(k + ':' + this[k]);
    }
    return '{' + s.join() + '}';
};
x.toString(); // returns something more useful

Nó thậm chí còn tốt hơn khi bạn xác định một kiểu mới:

function X()
{
    this.foo = 1;
    this.bar = true;
    this.baz = 'quux';
}

X.prototype.toString = /* same function as before */

new X().toString(); // returns "{foo:1,bar:true,baz:quux}"

9
Mã này không giải quyết được vấn đề console.log của OP, ít nhất là không có trong node.js v0.10.*hoặc Chrome Version 32.0.1700.102. Trong khi gọi toString trực tiếp (lame) hoặc sử dụng kiểu ép buộc (lamer) sẽ hoạt động với điều này, console [/ info | log /] sử dụng toString cũ trước mod.
james_womack

1
Bây giờ là năm 2019 và cả nodejs và chrome đều có các đối tượng in đẹp, do đó, sự ép buộc (khi bạn thêm đối tượng vào một chuỗi) là trường hợp sử dụng duy nhất mà bạn google câu hỏi này, tôi tin rằng.
Klesun

6

Nếu đối tượng do chính bạn xác định, bạn luôn có thể thêm ghi đè toString.

//Defined car Object
var car = {
  type: "Fiat",
  model: 500,
  color: "white",
  //.toString() Override
  toString: function() {
    return this.type;
  }
};

//Various ways to test .toString() Override
console.log(car.toString());
console.log(car);
alert(car.toString());
alert(car);

//Defined carPlus Object
var carPlus = {
  type: "Fiat",
  model: 500,
  color: "white",
  //.toString() Override
  toString: function() {
    return 'type: ' + this.type + ', model: ' + this.model + ', color:  ' + this.color;
  }
};

//Various ways to test .toString() Override
console.log(carPlus.toString());
console.log(carPlus);
alert(carPlus.toString());
alert(carPlus);


5

Với các ký tự mẫu :

class Foo {
  toString() {
     return 'I am foo';
  }
}

const foo = new Foo();
console.log(`${foo}`); // 'I am foo'

3

Thêm thuộc tính 'Symbol.toStringTag' vào đối tượng hoặc lớp tùy chỉnh.

Giá trị chuỗi được gán cho nó sẽ là mô tả chuỗi mặc định của nó vì nó được truy cập nội bộ bởi Object.prototype.toString()phương thức.

Ví dụ:

class Person {
  constructor(name) {
    this.name = name
  }
  get [Symbol.toStringTag]() {
    return 'Person';
  }
}

let p = new Person('Dan');
Object.prototype.toString.call(p); // [object Person]

Một số loại Javascript như Bản đồ và Lời hứa có một toStringTagký hiệu tích hợp được xác định

Object.prototype.toString.call(new Map());       // "[object Map]"
Object.prototype.toString.call(Promise.resolve()); // "[object Promise]"

Symbol.toStringTaglà một biểu tượng nổi tiếng , chúng tôi có thể tham chiếu nó và xác minh rằng các loại trên có thuộc tính Symbol.toStringTag -

new Map()[Symbol.toStringTag] // 'Map'
Promise.resolve()[Symbol.toStringTag] // 'Promise'

Điều này cùng với việc ghi đè toString()trực tiếp có phải là cách duy nhất để đạt được function MyObj() {} Object.prototype.toString.call(new MyObj()) // "[object MyObj]"không?
tonix

1
@tonix - Tôi nghĩ vậy ... Nếu có cách khác, vui lòng cho tôi biết;)
Danield

0

Nhật ký bảng điều khiển Chrome cho phép bạn kiểm tra đối tượng.


Đúng, điều đó đúng nếu tôi chỉ xuất đối tượng, điều này rất tiện lợi. Tuy nhiên, đôi khi tôi chỉ muốn xuất nó như một phần của chuỗi mà tôi có thể sử dụng để chứa các dữ liệu khác và sẽ rất tuyệt nếu tôi có thể tùy chỉnh biểu mẫu đó theo một cách nào đó.
defos1

6
Tôi chỉ phát hiện ra rằng bạn có thể sử dụng đối số bổ sung trong một console.log để đầu ra đối tượng inline với một chuỗi: console.log("this is my object:", obj).
defos1

0

- Thao tác này mất nhiều thời gian để hoàn thành và việc sử dụng nó không được khuyến khích theo tài liệu của mozilla: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/proto

-Hình như, các trình duyệt hiện đại không dùng .prototype và ECMA6 chỉ định bằng cách sử dụng thích hợp__proto__ thay thế.

Vì vậy, ví dụ: nếu bạn đang xác định bạn sở hữu vị trí địa lý đối tượng, bạn nên gọi thuộc tính __proto__ thay vì .prototype :

var  geoposition = {

        lat: window.pos.lat,
        lng: window.pos.lng
    };

geoposition.__proto__.toString = function(){ return "lat: "+this.lat+", lng: "+this.lng }
console.log("Searching nearby donations to: "+geoposition.toString());

0

Dưới đây là ví dụ về cách xâu chuỗi đối tượng Bản đồ:

  Map.prototype.toString = function() {

    let result = {};

    this.forEach((key, value) => { result[key] = value;});

    return JSON.stringify(result);
  };

-1

Bạn có thể cung cấp cho bất kỳ đối tượng tùy chỉnh nào các phương thức toString của riêng chúng hoặc viết một phương thức chung mà bạn có thể gọi trên đối tượng bạn đang xem-

Function.prototype.named= function(ns){
    var Rx=  /function\s+([^(\s]+)\s*\(/, tem= this.toString().match(Rx) || "";
    if(tem) return tem[1];
    return 'unnamed constructor'
}

function whatsit(what){
    if(what===undefined)return 'undefined';
    if(what=== null) return 'null object';
    if(what== window) return 'Window object';
    if(what.nodeName){
        return 'html '+what.nodeName;
    }
    try{
        if(typeof what== 'object'){
            return what.constructor.named();
        }
    }
    catch(er){
        return 'Error reading Object constructor';
    }
    var w=typeof what;
    return w.charAt(0).toUpperCase()+w.substring(1);
}

-1

Thay vì ghi đè toString(), nếu bạn bao gồm Thư viện JavaScript nguyên mẫu , bạn có thể sử dụngObject.inspect() để có được một biểu diễn hữu ích hơn nhiều.

Hầu hết các khuôn khổ phổ biến bao gồm một cái gì đó tương tự.


-1

Bạn có thể mở rộng hoặc ghi đè trong JS

String.prototype.toString = function() {
    return this + "..."
}
document.write("Sergio".toString());


Làm thế nào để điều này thêm bất cứ điều gì vào các câu trả lời năm 2011 cung cấp cùng một giải pháp?
Dan Dascalescu

-3
A simple format Date function using Javascript prototype, it can be used for your purpose

https://gist.github.com/cstipkovic/3983879 :

Date.prototype.formatDate = function (format) {
    var date = this,
        day = date.getDate(),
        month = date.getMonth() + 1,
        year = date.getFullYear(),
        hours = date.getHours(),
        minutes = date.getMinutes(),
        seconds = date.getSeconds();

    if (!format) {
        format = "MM/dd/yyyy";
    }

    format = format.replace("MM", month.toString().replace(/^(\d)$/, '0$1'));

    if (format.indexOf("yyyy") > -1) {
        format = format.replace("yyyy", year.toString());
    } else if (format.indexOf("yy") > -1) {
        format = format.replace("yy", year.toString().substr(2, 2));
    }

    format = format.replace("dd", day.toString().replace(/^(\d)$/, '0$1'));

    if (format.indexOf("t") > -1) {
        if (hours > 11) {
            format = format.replace("t", "pm");
        } else {
            format = format.replace("t", "am");
        }
    }

    if (format.indexOf("HH") > -1) {
        format = format.replace("HH", hours.toString().replace(/^(\d)$/, '0$1'));
    }

    if (format.indexOf("hh") > -1) {
        if (hours > 12) {
            hours -= 12;
        }

        if (hours === 0) {
            hours = 12;
        }
        format = format.replace("hh", hours.toString().replace(/^(\d)$/, '0$1'));
    }

    if (format.indexOf("mm") > -1) {
        format = format.replace("mm", minutes.toString().replace(/^(\d)$/, '0$1'));
    }

    if (format.indexOf("ss") > -1) {
        format = format.replace("ss", seconds.toString().replace(/^(\d)$/, '0$1'));
    }

    return format;
};
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.