《JavaScript面向对象精要》笔记

最近读了Nicholas大神的另一本书。这本书比较久了,不涉及ES6的部分。虽然ES6中的class更加适合面向对象编程。但这本书中的构造函数,原型,继承等也是非常需要了解的。这里只记下了读的过程中觉得不熟悉的地方,因此只适合自己看,算是一个备忘录吧。

鉴别原始类型

鉴别原始类型的最佳方法是使用typeof操作符,返回的值分别是stringnumberbooleanundefined。注意其中并没有null,这是因为typeof null得到的是object

判断一个值是否非空类型的最佳方法是直接和null比较:

1
value === null;

鉴别引用类型

函数可以直接使用typeof操作符,返回值是'function'
其他引用类型需要使用instanceof
比较特殊的是数组,虽然也可以使用instanceof,但当把一个数组在一个网页的不同iframe间传递时,instanceof不能识别它,因为那个数组是来自不同框架的Array的实例。

内建类型实例化

内建引用类型有字面形式。例如:

1
2
3
4
var book = {
name: 'xxx',
year: 2017
};

虽然使用字面形式并没有调用new Object(),但是JavaScript引擎背后做的工作和new Object()一样,除了没有调用构造函数

正则表达式字面形式的优势

javascript中正则表达式可以使用字面形式而不是RegExp构造函数来定义。使用字面形式比较方便的一个原因是不需要担心字符串中的转义字符。除非需要通过一个或多个字符串动态构造正则表达式,否则都建议使用字面形式而不是构造函数。

为什么字符串字面量可以当做一个对象使用?

当读取字符串、数字或布尔值时,原始封装类型将被自动创建。例如:

1
2
3
var name = 'xxx';
var firstChar = name.charAt(0);
console.log(firstChar); // 'x'

在背后发生的实情如下:

1
2
3
4
5
6
// what the JavaScript engine dose
var name = 'xxx';
var temp = new String(name);
var firstChar = temp.charAt(0);
temp = null;
console.log(firstChar); // 'x'

为了测试这一点,可以试着给字符串添加一个属性看看它是不是对象:

1
2
3
4
var name = 'xxx';
name.last = 'aaa';

console.log(name.last); // undefined

手动创建原始封装类型实际会创建出一个object,这意味着typeof无法鉴别出你实际保存的数据的类型。

1
2
3
4
5
6
7
var name = new String('xxx');
var count = new Number(10);
var found = new Boolean(false);

console.log(typeof name); // 'object'
console.log(typeof fount); // 'object'
console.log(typeof found); // 'object'

函数不同于其他对象

使函数不同于其他对象的决定性特点是函数存在一个被称为[[Call]]的内部属性。内部属性不能通过代码访问,而是定义了函数执行时的行为。

函数的length属性

函数的length属性表明了该函数期望的参数个数。

1
2
function a(b, c, d){};
console.log(a.length); // 3

对象的属性探测

  • 自有属性 + 原型属性: in
  • 自有属性:.hasOwnProperty()

对象字面形式中定义访问器属性有特殊的语法

1
2
3
4
5
6
7
8
9
10
11
var person1 = {
_name: 'xxx',
get name() {
console.log('Reading name');
return this._name;
},
set name(value) {
console.log('Setting name');
this._name = value;
}
};

禁止修改对象

方法 特点
Object.preventExtensions() 不能再添加新属性
Object.seal() 不能再添加新属性,也不能删除属性或改变其类型;只能读写它的属性
Object.freeze() 不能添加或删除属性,不能改变属性类型,也不能写入任何数据属性;数据属性都为只读

构造函数省略小括号

如果没有需要传递给构造函数的参数,那么可以忽略小括号:

1
var person1 = new Person;

直接运行首字母大写的构造函数

如果直接运行首字母大写的构造函数,在严格模式下会抛出一个错误。非严格模式可以正常运行。

在函数内检查自己是否被new调用

可以再函数内部用instanceof来检查自己是否被new调用:
(MDN上.bind的polyfill有用到这个)

1
2
3
4
5
6
7
8
function Persion(name) {
if (this instanceof Person) {
// called with 'new'
}
else {
// called without 'new'
}
}