Javascript Number Prototype 直接设置值

Dom*_*nik 1 javascript prototype numbers

我尝试直接从原型方法设置一个数字。通常,会返回一个新值。

一个数字对象的this也是一个对象。但我想不是参考。(?)

我有这个:

Number.prototype.bitSet = function(bit) {
    return this | (1<<bit);
};
Run Code Online (Sandbox Code Playgroud)

但想要这个:

Number.prototype.bitSet = function(bit) {
        this.value = this | (1<<bit);
    };
Run Code Online (Sandbox Code Playgroud)

this.value 是一个伪属性。因为这可能是数字的参考,没有它,您将覆盖它。但问题是:这真的是对来源编号的引用吗?有可能这样做吗?将值直接分配给调用此方法的号码?

var num = 0; 
num.bitSet(9);
console.log(num); // num = 512
Run Code Online (Sandbox Code Playgroud)

顺便提一句。chrome 控制台为数字打印 [[PrimitiveValue]]。

T.J*_*der 6

TL;DR - 你不能那样做,你的初始版本bitSet就是你需要如何定义它。使用时需要保存它的返回值,例如x = x.bitSet(2). 不过,如果您愿意,您可以创建自己的可变数字对象。(更多关于下面的内容。)

只是为了清楚起见(您可能知道这一点):JavaScript 同时具有数字原语Number 对象。通常,您正在处理原语。有效的原因Number.prototype是当一个方法被调用时,一个临时对象是使用原语的值创建的。除非有什么东西明确地保存了对象,否则就好像我们只是在处理原语。

数字在 JavaScript 中是不可变的。1所以你的bitSet方法不能改变它所调用的数值;相反,它必须返回一个带有更改的新数字(例如,您的原始版本)。

请注意,即使您可以更改Number对象的值,您也几乎不会在已分配给 的函数之外的代码中处理数字对象Number.prototype。例如:

Number.prototype.bitSet = function(bit) {
    return this | (1<<bit);
};
var x = 32;
x = x.bitSet(2);
console.log(x); // 36
console.log(typeof x); // "number", not "object"
var o = new Number(36);
console.log(typeof o); // "object"
Run Code Online (Sandbox Code Playgroud)

在上面,当x = x.bitSet(2);被执行时,数字原语被转换为一个临时Number对象,你的bitSet方法被调用,然后结果就是你的bitSet方法返回的结果;除非bitSetthis某处存储一些东西,否则临时对象将被丢弃。(这是理论;事实上,如果 JavaScript 引擎可以确定函数中的代码只使用该数字,就好像它是原始数字一样,它很可能会完全优化掉该对象。)

所以假设在我上面的代码中,我们做了一些事情来改变该行中Number对象的状态x.bitSet(2)。由于该对象是临时的并且没有存储在任何地方(除非我们存储它;它不在 中xx包含一个原始数字),我们存储在该对象上的任何内容都将丢失。我们甚至可以证明:

Number.prototype.test = function() {
  this.foo = Math.random();
  console.log("this.foo", this.foo); // some number
};
var x = 42;
x.test();
console.log(typeof x);       // "number", not "object"
console.log("x.foo", x.foo); // undefined
Run Code Online (Sandbox Code Playgroud)

this绝对是一个对象,我们向它添加了一个属性并使用了该属性。但x还是有原始的。

不过,您可以拥有自己的可变数字类型:

function MyNumber(value) {
    this.value = typeof value === "number" ? value : 0;
}
MyNumber.prototype.bitSet = function(bit) {
    this.value = this.value | (1 << bit);
};
MyNumber.prototype.valueOf = function() {
    return this.value;
};
MyNumber.prototype.toString = function() {
    return this.value.toString();
};

// Usage:
var m = new MyNumber(42);
m.bitSet(2);
console.log(String(m)); // "46"
var n = m + 5;
console.log(n);         // 51
Run Code Online (Sandbox Code Playgroud)

valueOf任何时候 JavaScript 引擎需要将您的数字对象转换为数字时都会调用该函数。toString当 JavaScript 引擎需要将您的数字对象转换为字符串时调用。

或者在 ES2015 中:

class MyNumber {
    constructor(value) {
      this.value = typeof value === "number" ? value : 0;
    }
    bitSet(bit) {
      this.value = this.value | (1 << bit);
    }
    valueOf() {
      return this.value;
    }
    toString() {
      return this.value.toString();
    }
}

// Usage:
var m = new MyNumber(42);
m.bitSet(2);
console.log(String(m)); // "46"
var n = m + 5;
console.log(n); // 51
Run Code Online (Sandbox Code Playgroud)


1 “数字在 JavaScript 中是不可变的”从技术上讲,这不是真的。原始数字是不可变的,但Number对象是可变的——但是它们的底层数值(规范所称的[[NumberData]])是不能改变的。(Number对象可以具有其他可以更改状态的属性,而不是它们的数值。)因此,“数字在 JavaScript 中不可变”是一个合理的速记语句,如果不完全正确的话。