我尝试直接从原型(prototype)方法中设置一个数字。
通常,会返回一个新值。
this 一个数字对象,也是一个对象。但我想不是引用。 (?)
我有这个:
Number.prototype.bitSet = function(bit) {
return this | (1<<bit);
};
但是想要这个:
Number.prototype.bitSet = function(bit) {
this.value = this | (1<<bit);
};
this.value 是一个伪属性。因为这应该是数字的引用,如果没有它,您将覆盖它。但问题是:这真的是引用源号吗?有可能这样做吗?直接给调用这个方法的号码赋值?
var num = 0;
num.bitSet(9);
console.log(num); // num = 512
顺便说一句。 chrome 控制台打印 [[PrimitiveValue]] 作为数字。
TL;DR - 你不能那样做,bitSet
的初始版本是你需要定义它的方式。使用它时需要保存它的返回值,例如,x = x.bitSet(2)
。不过,如果愿意,您可以创建自己的可变数字对象。 (更多内容见下文。)
为了清楚起见(您可能知道这一点):JavaScript 有数字原语 和数字
对象。通常,您正在处理原语。 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"
在上面,当x = x.bitSet(2);
被执行时,数字primitive被转换为一个临时的Number
对象,您的 bitSet
方法被调用,然后结果就是您的 bitSet
方法返回的任何内容;除非 bitSet
做了一些事情来将 this
存储在某个地方,否则临时对象将被丢弃。 (这就是理论;事实上,如果您的 JavaScript 引擎可以确定您的函数中的代码只使用该数字,就好像它是原始数字一样,那么它可能会完全优化对象。)
所以假设在我上面的代码中,我们做了一些事情来改变 x.bitSet(2)
行中的 Number
对象的状态。因为那个对象是临时的并且没有存储在任何地方(除非我们存储它;它不在x
中,x
包含一个原始数字),无论我们存储在对象上的将丢失。我们甚至可以证明:
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
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
只要 JavaScript 引擎需要将您的数字对象转换为数字,就会调用 valueOf
函数。 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
1 “JavaScript 中的数字不可变” 从技术上讲,这不是真的。 原始 数字不是可变的,但 Number
对象是 — 但它们的基础数值(规范称之为 [[NumberData]]
)不能被改变。 (Number
对象可以有其他状态可以改变的属性,只是不能改变它们的数值。)所以“数字在 JavaScript 中是不可变的”是一个合理的速记声明,即使不是完全正确。