深入理解JavaScript系列(18):面向对象编程之E(9)

另一方面,可以由构造函数来创建对象,但如果对象的[[Prototype]]属性和构造函数的prototype属性的值设置的是一样的话,instanceof检查的时候会返回true:

复制代码 代码如下:


function B() {}
var b = new B();
 
alert(b instanceof B); // true
 
function C() {}
 
var __proto = {
  constructor: C
};
 
C.prototype = __proto;
b.__proto__ = __proto;
 
alert(b instanceof C); // true
alert(b instanceof B); // false

原型可以存放方法并共享属性
大部分程序里使用原型是用来存储对象的方法、默认状态和共享对象的属性。

事实上,对象可以拥有自己的状态 ,但方法通常是一样的。 因此,为了内存优化,方法通常是在原型里定义的。 这意味着,这个构造函数创建的所有实例都可以共享找个方法。

复制代码 代码如下:


function A(x) {
  this.x = x || 100;
}
 
A.prototype = (function () {
 
  // 初始化上下文
  // 使用额外的对象
 
  var _someSharedVar = 500;
 
  function _someHelper() {
    alert('internal helper: ' + _someSharedVar);
  }
 
  function method1() {
    alert('method1: ' + this.x);
  }
 
  function method2() {
    alert('method2: ' + this.x);
    _someHelper();
  }
 
  // 原型自身
  return {
    constructor: A,
    method1: method1,
    method2: method2
  };
 
})();
 
var a = new A(10);
var b = new A(20);
 
a.method1(); // method1: 10
a.method2(); // method2: 10, internal helper: 500
 
b.method1(); // method1: 20
b.method2(); // method2: 20, internal helper: 500
 
// 2个对象使用的是原型里相同的方法
alert(a.method1 === b.method1); // true
alert(a.method2 === b.method2); // true

读写属性

正如我们提到,读取和写入属性值是通过内部的[[Get]]和[[Put]]方法。这些内部方法是通过属性访问器激活的:点标记法或者索引标记法:

复制代码 代码如下:


// 写入
foo.bar = 10; // 调用了[[Put]]
 
console.log(foo.bar); // 10, 调用了[[Get]]
console.log(foo['bar']); // 效果一样


让我们用伪代码来看一下这些方法是如何工作的:

[[Get]]方法

[[Get]]也会从原型链中查询属性,所以通过对象也可以访问原型中的属性。

O.[[Get]](P):

复制代码 代码如下:


// 如果是自己的属性,就返回
if (O.hasOwnProperty(P)) {
  return O.P;
}
 
// 否则,继续分析原型
var __proto = O.[[Prototype]];
 
// 如果原型是null,返回undefined
// 这是可能的:最顶层Object.prototype.[[Prototype]]是null
if (__proto === null) {
  return undefined;
}
 
// 否则,对原型链递归调用[[Get]],在各层的原型中查找属性
// 直到原型为null
return __proto.[[Get]](P)


请注意,因为[[Get]]在如下情况也会返回undefined:

复制代码 代码如下:


if (window.someObject) {
  ...
}


这里,在window里没有找到someObject属性,然后会在原型里找,原型的原型里找,以此类推,如果都找不到,按照定义就返回undefined。

注意:in操作符也可以负责查找属性(也会查找原型链):

复制代码 代码如下:


if ('someObject' in window) {
  ...
}


这有助于避免一些特殊问题:比如即便someObject存在,在someObject等于false的时候,第一轮检测就通不过。

[[Put]]方法

[[Put]]方法可以创建、更新对象自身的属性,并且掩盖原型里的同名属性。

O.[[Put]](P, V):

复制代码 代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgfgzd.html