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

关于调用内置构造函数,使用还是不适用new操作符没有通用规则,取决于构造函数。 例如Array或Function当使用new操作符的构造函数或者不使用new操作符的简单函数使用产生相同的结果的:

复制代码 代码如下:


var a = Array(1, 2, 3); // [object Array]
var b = new Array(1, 2, 3); // [object Array]
var c = [1, 2, 3]; // [object Array]
 
var d = Function(''); // [object Function]
var e = new Function(''); // [object Function]


有些操作符使用的时候,也有一些显示和隐式转化:

复制代码 代码如下:


var a = 1;
var b = 2;
 
// 隐式
var c = a + b; // 3, number
var d = a + b + '5' // "35", string
 
// 显式
var e = '10'; // "10", string
var f = +e; // 10, number
var g = parseInt(e, 10); // 10, number
 
// 等等

属性的特性

所有的属性(property) 都可以有很多特性(attributes)。

1.{ReadOnly}——忽略向属性赋值的写操作尝,但只读属性可以由宿主环境行为改变——也就是说不是“恒定值” ;
2.{DontEnum}——属性不能被for..in循环枚举
3.{DontDelete}——糊了delete操作符的行为被忽略(即删不掉);
4.{Internal}——内部属性,没有名字(仅在实现层面使用),ECMAScript里无法访问这样的属性。

注意,在ES5里{ReadOnly},{DontEnum}和{DontDelete}被重新命名为[[Writable]],[[Enumerable]]和[[Configurable]],可以手工通过Object.defineProperty或类似的方法来管理这些属性。

复制代码 代码如下:


var foo = {};
 
Object.defineProperty(foo, "x", {
  value: 10,
  writable: true, // 即{ReadOnly} = false
  enumerable: false, // 即{DontEnum} = true
  configurable: true // 即{DontDelete} = false
});
 
console.log(foo.x); // 10
 
// 通过descriptor获取特性集attributes
var desc = Object.getOwnPropertyDescriptor(foo, "x");
 
console.log(desc.enumerable); // false
console.log(desc.writable); // true
// 等等

内部属性和方法

对象也可以有内部属性(实现层面的一部分),并且ECMAScript程序无法直接访问(但是下面我们将看到,一些实现允许访问一些这样的属性)。 这些属性通过嵌套的中括号[[ ]]进行访问。我们来看其中的一些,这些属性的描述可以到规范里查阅到。

每个对象都应该实现如下内部属性和方法:

1.[[Prototype]]——对象的原型(将在下面详细介绍)
2.[[Class]]——字符串对象的一种表示(例如,Object Array ,Function Object,Function等);用来区分对象
3.[[Get]]——获得属性值的方法
4.[[Put]]——设置属性值的方法
5.[[CanPut]]——检查属性是否可写
6.[[HasProperty]]——检查对象是否已经拥有该属性
7.[[Delete]]——从对象删除该属性
8.[[DefaultValue]]返回对象对于的原始值(调用valueOf方法,某些对象可能会抛出TypeError异常)。
通过Object.prototype.toString()方法可以间接得到内部属性[[Class]]的值,该方法应该返回下列字符串: "[object " + [[Class]] + "]" 。例如:

复制代码 代码如下:


var getClass = Object.prototype.toString;
 
getClass.call({}); // [object Object]
getClass.call([]); // [object Array]
getClass.call(new Number(1)); // [object Number]
// 等等


这个功能通常是用来检查对象用的,但规范上说宿主对象的[[Class]]可以为任意值,包括内置对象的[[Class]]属性的值,所以理论上来看是不能100%来保证准确的。例如,document.childNodes.item(...)方法的[[Class]]属性,在IE里返回"String",但其它实现里返回的确实"Function"。

复制代码 代码如下:


// in IE - "String", in other - "Function"
alert(getClass.call(document.childNodes.item));

构造函数

因此,正如我们上面提到的,在ECMAScript中的对象是通过所谓的构造函数来创建的。

Constructor is a function that creates and initializes the newly created object.
构造函数是一个函数,用来创建并初始化新创建的对象。
对象创建(内存分配)是由构造函数的内部方法[[Construct]]负责的。该内部方法的行为是定义好的,所有的构造函数都是使用该方法来为新对象分配内存的。

而初始化是通过新建对象上下上调用该函数来管理的,这是由构造函数的内部方法[[Call]]来负责任的。

注意,用户代码只能在初始化阶段访问,虽然在初始化阶段我们可以返回不同的对象(忽略第一阶段创建的tihs对象):

复制代码 代码如下:

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

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