Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
amenzai committed Jul 29, 2018
1 parent 95bb150 commit f05cc93
Show file tree
Hide file tree
Showing 6 changed files with 654 additions and 133 deletions.
7 changes: 4 additions & 3 deletions SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* [this简介](chapter3/section3.2.md)
* [prototype对象](chapter3/section3.3.md)
* [Object对象](chapter3/section3.4.md)
* [面向对象编程](chapter3/section3.5.md)
* [严格模式](chapter3/section3.5.md)
* [DOM]('')
* [Document对象](chapter4/section4.1.md)
* [Element对象](chapter4/section4.2.md)
Expand All @@ -48,8 +48,9 @@
* [Web Worker](chapter5/section5.8.md)
* [SSE](chapter5/section5.9.md)
* [requestAnimationFrame](chapter5/section5.10.md)
* [语法专题]('')
* [异步操作](chapter6/section6.1.md)
* [异步操作]('')
* [概述](chapter6/section6.1.md)
* [定时器](chapter6/section6.2.md)
* [数据结构]('')
* [](chapter7/section7.1.md)
* [队列](chapter7/section7.2.md)
Expand Down
169 changes: 134 additions & 35 deletions chapter3/section3.3.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,46 @@
# prototype 对象
# 对象的继承

## 作用
## 概述

### 构造函数缺点

通过构造函数为实例对象定义属性,虽然很方便,但是有一个缺点。同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费。

```js
function Cat(name, color) {
this.name = name;
this.color = color;
this.meow = function () {
console.log('喵喵');
};
}

var cat1 = new Cat('大毛', '白色');
var cat2 = new Cat('二毛', '黑色');

cat1.meow === cat2.meow
// false
```
上面代码中,cat1和cat2是同一个构造函数的两个实例,它们都具有meow方法。由于meow方法是生成在每个实例对象上面,所以两个实例就生成了两次。也就是说,每新建一个实例,就会新建一个meow方法。这既没有必要,又浪费系统资源,因为所有meow方法都是同样的行为,完全应该共享。

这个问题的解决方法,就是 JavaScript 的原型对象(prototype)。

### prototype 属性的作用
定义所有实例对象共享的属性和方法。

## 原型链
### 原型链
JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……

对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。

Object.prototype对象的原型是null,由于null没有任何属性,所以原型链到此为止。

## constructor 属性
### constructor 属性
prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。

constructor属性的作用,是分辨原型对象到底属于哪个构造函数。

## instanceof 运算符
### instanceof 运算符
instanceof运算符返回一个布尔值,表示某个对象是否为指定的构造函数的实例。

instanceof运算符的左边是实例对象,右边是构造函数。它会检查右边构建函数的原型对象(prototype),是否在左边对象的原型链上。因此,下面两种写法是等价的。
Expand All @@ -24,47 +51,119 @@ v instanceof Vehicle
Vehicle.prototype.isPrototypeOf(v)
```

## Object.getPrototypeOf()
Object.getPrototypeOf方法返回一个对象的原型。这是获取原型对象的标准方法。
## 构造函数的继承
让一个构造函数继承另一个构造函数,是非常常见的需求。

这可以分成两步实现。第一步是在子类的构造函数中,调用父类的构造函数。

```js
// 空对象的原型是Object.prototype
Object.getPrototypeOf({}) === Object.prototype
// true

// 函数的原型是Function.prototype
function f() {}
Object.getPrototypeOf(f) === Function.prototype
// true

// f 为 F 的实例对象,则 f 的原型是 F.prototype
var f = new F();
Object.getPrototypeOf(f) === F.prototype
// true
function Sub(value) {
// this是子类实例
Super.call(this);
this.prop = value;
}
```

## Object.setPrototypeOf()
Object.setPrototypeOf方法可以为现有对象设置原型,返回一个新对象。
第二步,是让子类的原型指向父类的原型,这样子类就可以继承父类原型。

Object.setPrototypeOf方法接受两个参数,第一个是现有对象,第二个是原型对象。
```js
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.prototype.method = '...';
```
另外一种写法是Sub.prototype等于一个父类实例。
```js
Sub.prototype = new Super();
```
上面这种写法也有继承的效果,但是子类会具有父类实例的方法。有时,这可能不是我们需要的,所以不推荐使用这种写法。

## 多重继承

```js
var a = {x: 1};
var b = Object.setPrototypeOf({}, a);
// 等同于
// var b = {__proto__: a};
function M1() {
this.hello = 'hello';
}

function M2() {
this.world = 'world';
}

function S() {
M1.call(this);
M2.call(this);
}

b.x // 1
// 继承 M1
S.prototype = Object.create(M1.prototype);
// 继承链上加入 M2
Object.assign(S.prototype, M2.prototype);

// 指定构造函数
S.prototype.constructor = S;

var s = new S();
s.hello // 'hello:'
s.world // 'world'
```
上面代码中,子类S同时继承了父类M1和M2。

## 模块

### 基本的实现方法

```js
var module1 = {
count: 0,
m1: function() {

}
}
module1.m1()
```
有个问题,外部代码可以直接改变内部计数器的值。
```js
module1.count = 10;
```

### 封装私有变量
```js
var module1 = (function () {
 var _count = 0;
 var m1 = function () {
  //...
 };
 var m2 = function () {
  //...
 };
 return {
  m1 : m1,
  m2 : m2
 };
})();
```

## Object.create()
该方法接受一个对象作为参数,然后以它为原型,返回一个实例对象。该实例完全继承原型对象的属性。
### 推荐写法

```js
(function($, window, document) {

function go(num) {
}

function handleEvents() {
}

object.create方法生成的新对象,动态继承了原型。在原型上添加或修改任何方法,会立刻反映在新对象之上。
function initialize() {
}

除了对象的原型,Object.create方法还可以接受第二个参数。该参数是一个属性描述对象,它所描述的对象属性,会添加到实例对象,作为该对象自身的属性。
function dieCarouselDie() {
}

## Object.prototype.isPrototypeOf()
对象实例的isPrototypeOf方法,用来判断一个对象是否是另一个对象的原型。
//attach to the global scope
window.finalCarousel = {
init : initialize,
destroy : dieCouraselDie
}

只要某个对象处在原型链上,isPrototypeOf都返回true。
})( jQuery, window, document );
```
85 changes: 72 additions & 13 deletions chapter3/section3.4.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,77 @@
# Object对象
# Object对象的相关方法

通过原型链,对象的属性分成两种:自身的属性和继承的属性。JavaScript 语言在Object对象上面,提供了很多相关方法,来处理这两种不同的属性。

## Object.getPrototypeOf()
Object.getPrototypeOf方法返回参数对象的原型。这是获取原型对象的标准方法。

```js
// 空对象的原型是Object.prototype
Object.getPrototypeOf({}) === Object.prototype
// true

// 函数的原型是Function.prototype
function f() {}
Object.getPrototypeOf(f) === Function.prototype
// true

// f 为 F 的实例对象,则 f 的原型是 F.prototype
var f = new F();
Object.getPrototypeOf(f) === F.prototype
// true
```

## Object.setPrototypeOf()
Object.setPrototypeOf方法可以为参数对象设置原型,返回一个新对象。

Object.setPrototypeOf方法接受两个参数,第一个是现有对象,第二个是原型对象。

```js
var a = {x: 1};
var b = Object.setPrototypeOf({}, a);
// 等同于
// var b = {__proto__: a};

b.x // 1
```

## Object.create()
该方法接受一个对象作为参数,然后以它为原型,返回一个实例对象。该实例完全继承原型对象的属性。

object.create方法生成的新对象,动态继承了原型。在原型上添加或修改任何方法,会立刻反映在新对象之上。

除了对象的原型,Object.create方法还可以接受第二个参数。该参数是一个属性描述对象,它所描述的对象属性,会添加到实例对象,作为该对象自身的属性。

```js
var obj = Object.create({}, {
p1: {
value: 123,
enumerable: true,
configurable: true,
writable: true,
},
p2: {
value: 'abc',
enumerable: true,
configurable: true,
writable: true,
}
});

// 等同于
var obj = Object.create({});
obj.p1 = 123;
obj.p2 = 'abc';
```

## Object.prototype.isPrototypeOf()
对象实例的isPrototypeOf方法,用来判断一个对象是否是另一个对象的原型。

只要某个对象处在原型链上,isPrototypeOf都返回true。

## Object.prototype.__proto__
实例对象的__proto__属性(前后各两个下划线),返回该对象的原型。该属性可读写。

## Object.getOwnPropertyNames()
返回一个数组,成员是对象本身的所有属性的键名,不包含继承的属性键名。

Expand Down Expand Up @@ -72,15 +142,4 @@ function copyObject(orig) {
Object.getOwnPropertyDescriptors(orig)
);
}
```
## 其他常用方法
- Object.getPrototypeOf()
返回参数对象的原型。
- Object.setPrototypeOf()
为参数对象设置原型,返回该参数对象。它接受两个参数,第一个是现有对象,第二个是原型对象。
- Object.create()
该方法接受一个对象作为参数,然后以它为原型,返回一个实例对象。该实例完全继承原型对象的属性。
- Object.prototype.isPrototypeOf()
判断该对象是否为参数对象的原型
- Object.prototype.__proto__()
返回该对象的原型,属性可读写。
```
Loading

0 comments on commit f05cc93

Please sign in to comment.