finish book1
This commit is contained in:
parent
446366a32f
commit
024c9d70ec
@ -209,4 +209,120 @@
|
||||
// 3
|
||||
```
|
||||
* 混合对象“类”
|
||||
*
|
||||
* 设计模式:实例化,继承,(相对)多态
|
||||
* 多态并不能表示子类和父类有关联,子类得到的只是父类的一个副本,类的继承实际上就是复制
|
||||
* super关键字用于访问和调用一个对象的父对象上的函数。`super.prop`和`super[expr]`表达式在类和对象字面量任何方法定义中都是有效的。
|
||||
* js本身并不支持多重继承
|
||||
* 类意味着复制,js并不会自动创建对象的副本
|
||||
* 混入模式可以模拟类的复制行为,但是会产生丑陋并且脆弱的语法。
|
||||
* 而且对象(函数)只能复制引用,无法复制被引用的对象或者函数本身,所以在js中模拟类是得不偿失的,虽然可以解决当前的问题,但是可能会留下更多的隐患
|
||||
* 原型
|
||||
* `Object.create(...)`创建一个对象并将其`prototype`关联到指定对象
|
||||
* 所有对象的`prototype`最终都指向了内置的`Object.prototype`其中包含类如`.toString();.valueOf()`之类的方法
|
||||
* 分析:如果foo不直接存在于obj上而是存在于原型链上层时会出现的三种情况
|
||||
* 如果上层的foo是普通的数据访问属性,并且没有被标记为只读,那就会在对象上直接创建foo属性,它是遮蔽属性
|
||||
* 如果上层的foo是只读属性的话,严格模式下会抛出一个错误,正常模式下静默失败,可以理解为obj继承了foo但是foo是只读属性,所以不可更改(实际上js并没有继承这一概念,只是为了理解、
|
||||
* 而且仅限于 = 赋值中,使用`Object.defineProperty()`并不会受到任何影响
|
||||
* 如果上层的foo存在且是一个setter,就会调用这个setter,foo不会重新定义也不会直接添加到obj中
|
||||
* 模仿类:
|
||||
* 利用所有函数都会拥有一个名为`prototype`的共有且不可枚举的属性,并且会指向另一个对象
|
||||
* 通过`new foo()`最后我们得到了两个对象,并且他们互相关联,实际上new并没有直接创建关联,这个关联只是一个意外的副作用
|
||||
* new 会劫持所有的函数并用构造对象的形式来调用它,而且无论如何都会构造一个对象,换句话说在js中对于“构造函数”最准确的解释是:所有带new的函数调用
|
||||
* 函数被创建的时候会默认在其`prototype`中声明一个不可枚举的`construct`属性,指向它自己,使用`new`创建一个对象的时候由于其`prototype`会链接到函数的`prototype`上,所以`obj.construct`会委托到`prototype`上也就是指向了函数,但是如果那个函数重定义了整个`prototype`,再去查找`obj.construct`就会一层一层委托到`Object`的`construct`上,也就是指向`Object`,总结一下就是说construct并不能表示由“某函数”创建,尽量不要使用它以减少麻烦
|
||||
* 实现类的继承,实际上是委托
|
||||
* 方法一`Bar.prototype = Object.create(Foo.prototype)`
|
||||
* 方法二`Object.setPrototypeOf(Bar.prototype, Foo.prototype)` ES6语法
|
||||
* `__proto__`存在于`Object.prototype`中,看起来像一个属性,但是更像是getter/setter
|
||||
* 创建关联最好的方式不是创建一个类,而是使用`Object.create()`
|
||||
* 所有包含"继承"之类的词语都不适合形容js的操作,更应该使用"委托",因为“继承”是复制操作(由上至下的),"委托"是链接操作(由下至上的)
|
||||
* 行为委托
|
||||
* js中`[[prototype]]`这个机制的本质就是**对象之间的关联关系**
|
||||
* 在正常的模仿类的设计中,上代码!
|
||||
```js
|
||||
function Foo(who) {
|
||||
this.me = who
|
||||
}
|
||||
Foo.prototype.indetify = function() {
|
||||
return "I am" + this.me
|
||||
}
|
||||
function Bar(who) {
|
||||
Foo.call(this, who)
|
||||
}
|
||||
Bar.prototype = Object.create(Foo.prototype)
|
||||
Bar.prototype.speak = function() {
|
||||
alert('Hello,'+ this.indetify() + '.')
|
||||
}
|
||||
var b1 = new Bar('b1')
|
||||
var b2 = new Bar('b2')
|
||||
b1.speak()
|
||||
b2.speak()
|
||||
```
|
||||
* 在es6的语法糖中,上代码!
|
||||
```js
|
||||
class Foo {
|
||||
constructor(who) {
|
||||
this.me = who
|
||||
}
|
||||
indetify(){
|
||||
return "I am" + this.me
|
||||
}
|
||||
}
|
||||
class Bar extends Foo {
|
||||
constructor(who) {
|
||||
super(who)
|
||||
}
|
||||
speak(){
|
||||
alert('Hello,'+ super.indetify() + '.')
|
||||
}
|
||||
}
|
||||
var b1 = new Bar('b1')
|
||||
var b2 = new Bar('b2')
|
||||
b1.speak()
|
||||
b2.speak()
|
||||
```
|
||||
* 在关联风格代码中的实现,上代码!
|
||||
```js
|
||||
var Foo = {
|
||||
init: function(who) {
|
||||
this.me = who
|
||||
},
|
||||
indetify: function() {
|
||||
return "I am" + this.me
|
||||
}
|
||||
}
|
||||
var Bar = Object.create(Foo)
|
||||
Bar.speak = function() {
|
||||
alert('Hello,'+ this.indetify() + '.')
|
||||
}
|
||||
var b1 = Object.create(Bar)
|
||||
b1.init('b1')
|
||||
var b2 = Object.create(Bar)
|
||||
b2.init('b2')
|
||||
b1.speak()
|
||||
b2.speak()
|
||||
```
|
||||
* 同为关联风格代码,但是进行了语法上的优化(es6中的简洁方法声明)(Object.setPrototypeOf后置关联)这样看起来舒服不少
|
||||
```js
|
||||
var Foo = {
|
||||
init(who) {
|
||||
this.me = who
|
||||
},
|
||||
indetify() {
|
||||
return "I am" + this.me
|
||||
}
|
||||
}
|
||||
var Bar = {
|
||||
speak() {
|
||||
alert('Hello,'+ this.indetify() + '.')
|
||||
}
|
||||
}
|
||||
Object.setPrototypeOf(Bar, Foo)
|
||||
var b1 = Object.create(Bar)
|
||||
b1.init('b1')
|
||||
var b2 = Object.create(Bar)
|
||||
b2.init('b2')
|
||||
b1.speak()
|
||||
b2.speak()
|
||||
```
|
||||
* instanceof 如果 Bar”继承了“Foo 那么就是 `Bar.prototype instanceof Foo => true`
|
||||
* 如果`Bar = Object.create(Foo)`则`Foo.isPrototypeOf(Bar) => true`,`Object.getPrototypeOf(Bar) === Foo => ture`
|
@ -54,30 +54,48 @@
|
||||
// console.log(test)
|
||||
// console.log(test1)
|
||||
|
||||
var obj = {
|
||||
// set a(val) {
|
||||
// this._a_ = val * 2
|
||||
// },
|
||||
// get a() {
|
||||
// return this._a_
|
||||
// },
|
||||
// var obj = {
|
||||
// // set a(val) {
|
||||
// // this._a_ = val * 2
|
||||
// // },
|
||||
// // get a() {
|
||||
// // return this._a_
|
||||
// // },
|
||||
|
||||
}
|
||||
Object.defineProperty(
|
||||
obj,
|
||||
'a',
|
||||
{
|
||||
set: function(val) {
|
||||
this._a_ = val * 2
|
||||
},
|
||||
get: function() {
|
||||
return this._a_
|
||||
},
|
||||
// }
|
||||
// Object.defineProperty(
|
||||
// obj,
|
||||
// 'a',
|
||||
// {
|
||||
// set: function(val) {
|
||||
// this._a_ = val * 2
|
||||
// },
|
||||
// get: function() {
|
||||
// return this._a_
|
||||
// },
|
||||
|
||||
writable: false,
|
||||
enumerable: true
|
||||
}
|
||||
)
|
||||
obj.a = 2
|
||||
console.log(obj)
|
||||
console.log(obj.a)
|
||||
// writable: false,
|
||||
// enumerable: true
|
||||
// }
|
||||
// )
|
||||
// obj.a = 2
|
||||
// console.log(obj)
|
||||
// console.log(obj.a)
|
||||
|
||||
function Foo(who) {
|
||||
this.me = who
|
||||
}
|
||||
Foo.prototype.indetify = function() {
|
||||
return "I am" + this.me
|
||||
}
|
||||
function Bar(who) {
|
||||
Foo.call(this, who)
|
||||
}
|
||||
Bar.prototype = Object.create(Foo.prototype)
|
||||
Bar.prototype.speak = function() {
|
||||
alert('Hello,'+ this.indetify() + '.')
|
||||
}
|
||||
var b1 = new Bar('b1')
|
||||
var b2 = new Bar('b2')
|
||||
b1.speak()
|
||||
b2.speak()
|
Loading…
x
Reference in New Issue
Block a user