Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.6 函数类 与 原型类 Functional Classes vs. Prototype Classes #136

Open
EthanLin-TWer opened this issue Mar 8, 2017 · 0 comments
Assignees

Comments

@EthanLin-TWer
Copy link
Owner

EthanLin-TWer commented Mar 8, 2017

函数类 Functional Classes

这个起源自上一节 #135 我们发现的事情了:装饰模式可以用来创建对象或为对象添加属性。当其服务于第一种目的——创建对象——时,装饰模式便退化成了一个简单的函数类(用于创建对象的函数,设计模式里的 constructor 型模式)。这种情形也是我们上节所说,可以使用 ES6 提供的 class 语法糖来简化代码并达到相同效果的场景。

image

又说回 move 函数每次都要重新创建一个新实例的事情。我们还是想重构这个点,因此,退一步回来,有两个事情需要做:

  • 将对象的方法还是移到全局下去
  • 使用类似于 obj.extend(obj, methods) 的函数批量将所有方法在构造时添加到对象上去

image

let Car = function(location) {
  let car = { location: location }
  extends(car, Car.methods) // extends 并不是 JavaScript 原生的方法
  return car
}

Car.methods = {
  move: function() {
    this.location++
  },
  on: function() { /* .. */ },
  off: function() { /* .. */ }
}

let taxi = Car(3)
let bus = Car(9)

taxi.move()
bus.move()

这样的解决方案其实是因为 JavaScript 没有原生类的支持而产生的方案。对比一下与静态语言的区别:

  • 类:使用函数来模拟类的属性、方法等属性,并通过设定恰当的 this 值来支持此技术
  • private 变量:没有类,也就没有类作用域,因此只能使用闭包,利用函数作用域来实现变量隐藏。但同时闭包作为一种函数级的方案更加灵活,在 Java 中,因为函数不能作为方法参数,要实现闭包同样的效果只能通过静态内部类来做到

原型类 Prototype Classes

使用函数类有两个问题:

  • 每次方法都是手动拷贝到对象上去的,是在应用程序的层级上解决这个问题
  • 每调用一次函数创建对象,都会生成一个新的完全相同的函数

于是我们就想,能不能不每个对象都拥有相同的属性或变量,类似于真正的面向对象的继承,我还是复用基类的,需要的时候向上查找就行了?当然可以。JavaScript 原生就提供了这个功能:prototype。

image

let Car = function(location) {
  let car = Object.create(Car.prototype)
  car.location = location 
  return car
}

Car.prototype.move = function() { this.location++ }
Car.prototype.on = function() { /* .. */ }
// Car.prototype = { move: function() {}, on: function() {} } 会直接覆写 `Car.prototype`,是不推荐的实践

let taxi = Car(3)
let bus = Car(9)

taxi.move()
bus.move()

主要的变化是:

  • method 改成了 prototype。其实 prototype 就只是 JS 为此场景提供的一个更有标识度的关键词,可以认为与 method 没什么区别,只是重命名了一下而已
  • Object.create(Car.prototype) 创建出来的对象,便会把它找不到的属性和方法 delegate 到 Car.prototype(这里就是我们定义的方法)上查找,我们就省去了 extends(obj, methods) 便达到了同样的效果
  1. 查找变量,究竟是按照作用域链,还是原型链?没有继承时,只按照作用域链查;两者都有时,查不到是先查原型链,还是作用域?设计个实验?
  2. Obj.prototype.constructor 有什么用?
  3. https://blog.oyanglul.us/javascript/understand-prototype.html
  4. new Function() 有什么意义和区别?难道不是只有类才可以 new?
  5. http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html
  6. http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014344997013405abfb7f0e1904a04ba6898a384b1e925000
  7. https://github.com/norfish/blog/wiki/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3JavaScrip%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E5%92%8C%E5%8E%9F%E5%9E%8B%E7%BB%A7%E6%89%BF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant