bal*_*ton 2 javascript function-prototypes
有人可以告诉我为什么结果是什么,而不是我期望的结果.这让我疯了!
var f = function(b){
console.log(this.config);
this.config.b = b;
}
f.prototype.config = {
a: 'a',
b: 'b'
};
var f1 = new f('bb');
var f2 = new f('bbb');
// logs
// { a: 'a', b: 'b' }
// { a: 'a', b: 'bb' }
// expected
// { a: 'a', b: 'b' }
// { a: 'a', b: 'b' }
Run Code Online (Sandbox Code Playgroud)
它不是被修改的原型,而是config你在原型上放置的对象.这是正确的行为,创建新实例时不会复制原型引用的对象.f1.config === f2.config,他们指向同一个对象.
原型链用于get操作的方式是:
this.config.config,所以我们继续下一步.undefined.(set操作的工作方式不同; set操作总是在它所设置的对象上更新或创建属性,从不进一步向下[原型?]原型链.)
因此,在您的情况下,由于您的实例没有config属性,我们将转到原型.由于原型确实具有config属性,因此使用它.该属性的值是一个对象的引用,所以如果你改变对象(通过分配到一个其属性),它的改变,别的也使用该对象将会看到的变化.
另一种看待它的方法是做一个图表:
+------+ +------+
| f1 | | f2 |
+------+ +------+
| |
+------+-------+
|
v
+--------------------+ +--------+
| [[Proto]] assigned | | config |
| via `new f` |------>| object |
+--------------------+ +--------+
|
+-------+-------+
| |
V v
+------------+ +------------+
| a property | | b property |
+------------+ +------------+
另一种思考方式是将函数和原型完全取出:
var pseudoProto = {}; // A stand-in for the prototype...
pseudoProto.config = { // ...with `config` on it
a: 'a',
b: 'b'
};
var f1 = {}; // A blank object...
f1.pseudo = pseudoProto; // ...referencing `pseudoProto`
var f2 = {}; // Another blank object...
f2.pseudo = pseudoProto; // ...also referencing `pseudoProto`
f1.pseudo.config.b = "bb"; // Change the `b` property on `config`
console.log(f2.pseudo.config.b); // Logs "bb", of course
Run Code Online (Sandbox Code Playgroud)
以一种非常真实的方式,这就是掩盖下发生的事情new f().你不能直接访问的属性f1和f2指向原型(规范调用它的实例[[Proto]]属性),但它是一个真实的东西,它真的存在.[仅供参考:ECMAScript规范的最新版本允许我们直接使用[[Proto]]属性执行一些操作,例如使用特定的[[Proto]](不通过函数)创建原始对象,但仍然不允许我们直接访问属性本身. ]
很多时候你希望所有实例共享同一个对象(例如,函数对象!),因此原型是那些对象引用的正确位置; 但是如果您希望每个实例都有自己的对象副本,则需要在构造函数中创建该对象.在你的情况下:
var f = function(b){
this.config = {
a: 'a',
b: b
};
}
var f1 = new f('bb');
console.log(f1.config);
var f2 = new f('bbb');
console.log(f2.config);
Run Code Online (Sandbox Code Playgroud)
// Logs
// { a: 'a', b: 'bb' }
// { a: 'a', b: 'bbb' }
(注意我移动了console.log语句,因此我们在结束时看到结果而不是中间状态.)