基于原型的JavaScript面向对象编程

2,065 views

Published on

Published in: Software, Technology
0 Comments
33 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,065
On SlideShare
0
From Embeds
0
Number of Embeds
11
Actions
Shares
0
Downloads
13
Comments
0
Likes
33
Embeds 0
No embeds

No notes for slide

基于原型的JavaScript面向对象编程

  1. 1. 基于原型的JavaScript面向对象编程 炎燎 手机搜狐 https://github.com/maxzhang http://maxzhang.github.io
  2. 2. 一切从对象开始 JavaScript是一种基于对象 (object-based) 的语言
  3. 3. Data types 原生类型(primitive type) • number • boolean • string • null • undefined 对象类型(object type) • everything else...
  4. 4. 对象的表现形式 { // JSON a: 1 } [1, 2] // Array /d+/i // RegExp function() {} // Function new Object(); // constructor // ... Note:函数(function)是一个特殊的对象,所有函数都是构造函数 Function的实例。
  5. 5. typeof运算符 x typeof x undefined “undefined” null “object” true或false “boolean” 任意数字或NaN “number” 任意字符串 “string” 任意函数 “function” 任意内置对象(非函数) “object” 任意宿主对象 由编译器各自实现的字符串,但不是 “undefined”、“boolean”、“number”或 “string”
  6. 6. 世界上最容易被误解的语言 JavaScript
  7. 7. JavaScript是不是面向对象语言?
  8. 8. 外界的三种评价 • JavaScript是面向对象语言 • JavaScript是基于对象的语言, 但不是真正的面向对 象 • JavaScript不是面向对象语言
  9. 9. 什么样的语言可 以称之为面向对 象语言?
  10. 10. 哪些是面向对象语言? • Java • C# • C++ • ... 它们都是基于类(class-based)的面向对象语言
  11. 11. 面向对象的三个基本特征 • 封装( Encapsulation ) • 继承( Inheritance ) • 多态( Polymorphism )
  12. 12. JavaScript是否 满足这几个特征 呢?
  13. 13. 封装——类 • JavaScript没有类(Class)的概念,取而代之的是构造函数 (constructor) • 所有函数(function)都是构造函数 function Foo() {} new Foo();
  14. 14. 封装——最简单的对象封装 key : value var cat1 = { name: '没头脑', color: 'red' }; 使用函数封装 var Cat = function(name, color) { // ... return { name: '不高兴', color: 'yellow' }; }; var cat2 = Cat();
  15. 15. 封装——构造函数 var Cat = function() { this.name = '没头脑'; this.color = 'red'; }; var cat = new Cat();
  16. 16. 封装——原型模式 var Cat = function() { }; Cat.prototype.name = '没头脑'; Cat.prototype.color = 'red'; var cat = new Cat();
  17. 17. 封装——私有变量 function Container(param) { function decrease() { if (secret > 0) { secret -= 1; return true; } else { return false; } } this.member = param; var secret = 3; var that = this; } this.service = function() { return decrease() ? that.member : null; }; 缺陷:原型方法不能享受到构造函数中的私有变量,并且本地方法不 能被继承。
  18. 18. 继承 • JavaScript是基于原型(prototype-based)的继承 • JavaScript无法做到接口继承,只能实现继承
  19. 19. 多态——重载(overload) var Foo = function() {}; Foo.prototype.method1 = function(a, b) { if (typeof a == "number" && typeof b == "number") { alert(a * b); } else if (typeof a == "string" && typeof b == "string") { alert(a + b); } else if (arguments.length == 3) { alert((a + b) * arguments[2]); } else { alert("输入错啦"); } }; JavaScript是弱类型语言,通过动态判断参数类型实现重载。
  20. 20. 多态——覆写(override) var Foo = function() {}; Foo.prototype.toString = function() { return "foo object"; }; alert(new Foo()); // alert "foo object"
  21. 21. JavaScript是一门十分动态的通用 面向对象语言 ecma-262是这么描述的 ECMAScript is an object-oriented programming language for performing computations and manipulating computational objects within a host environment. 参考:http://www.ecma-international.org/ecma-262/5.1/index.html#sec4.2
  22. 22. 基于原型的面向对象编程 • 构造函数(constructor) • 原型( prototype) • 原型链(prototype chain)
  23. 23. 构造函数和原型 • 所有构造函数都包含一个名为“prototype”的不可枚举 的属性,它就是原型 • 每个原型(prototype)对象又都包含一个名为 “constructor”的不可枚举的属性,它应该始终指向到 构造函数(constructor) function Foo() {} alert(Foo.prototype.constructor === Foo); // true
  24. 24. 构造函数的问题 重写预定义的prototype带来的问题 function Foo() {} Foo.prototype = {}; alert(Foo.prototype.constructor === Foo); // false alert(Foo.prototype.constructor === Object); // true
  25. 25. 修复构造函数的问题 第一种方法,为新的prototype添加一个constructor属性 function Foo() {} Foo.prototype = { constructor: Foo, method1: funciton() {} }; alert(Foo.prototype.constructor === Foo); // true 第二种方法,使用预定义的prototype对象 function Foo() {} Foo.prototype.method1 = function() {}; alert(Foo.prototype.constructor === Foo); // true
  26. 26. 原型链 • __proto__是理解原型链的关键对象 • 所有对象都包含一个__proto__属性,来实现对原型 (prototype)的隐式引用 • 原型链主要理解两种对象:使用new操作符实例化的 对象、函数(function)对象
  27. 27. 使用new操作符实例化对象的原型链(1) function Foo() {} var foo = new Foo(); alert(foo.__proto__ === Foo.prototype); // true 在chrome控制台下能看到可访问的__proto__属性
  28. 28. 使用new操作符实例化对象的原型链(2) 构造函数Foo的__proto__ alert(Foo.prototype.__proto__ === Object.prototype); // true foo的原型链
  29. 29. 函数(function)对象的原型链(1) 函数(function)是一个特殊的对象,所有函数都是构造函数 Function的实例 function Foo() {} alert(Foo.__proto__ === Object.prototype); // false alert(Foo.__proto__ === Function.prototype); // true
  30. 30. 函数(function)对象的原型链(2) alert(Function.__proto__ === Function.prototype); // true alert(Function.prototype.__proto__ === Object.prototype); // true Function的原型链
  31. 31. instanceof运算符 instanceof运算符返回一个指定的对象是否一个类的实例,格式如:A instanceof B。其中,左操作数必须是一个对象,右操作数必须是一个类 (构造函数)。 判断过程:如果函数B在对象A的原型链(prototype chain)中被发现, 那么instanceof操作符将返回true,否则返回false。 function Foo() {} var foo = new Foo(); alert(foo instanceof Foo); // true alert(foo instanceof Object); // true // foo原型链中没有Function.prototype alert(foo instanceof Function); // false alert(Foo instanceof Function); // true alert(Foo instanceof Object); // true alert(Function instanceof Function); // true alert(Object instanceof Function); // true alert(Function instanceof Object); // true
  32. 32. 基于原型的继承 • 使用prototype实现基于原型的继承以及属性共享 • 假定一个事实,子类可以访问到父类原型中定义的属 性 • 如何构建类继承的原型“链”?
  33. 33. 设想一个最简单的继承 function Animal() { alert('Animal init'); } Animal.prototype.sleep = function() { alert('Animal sleep'); }; var a1 = new Animal(); // alert Animal init a1.sleep(); // alert Animal sleep function Cat() { alert('Cat init'); } Cat.prototype = Animal.prototype; Cat.prototype.sleep = function() { alert('Cat sleep'); }; var c2 = new Cat(); // alert Cat init c2.sleep(); // alert Cat sleep a1.sleep(); // alert Cat sleep,这时候a1也输出了Cat sleep
  34. 34. 创建对象改进继承 function Cat() { alert('Cat init'); } Cat.prototype = new Animal(); // alert 'Animal init‘ var c2 = new Cat(); // alert Cat init c2的原型链
  35. 35. 使用空对象作为中介 function Cat() { alert('Cat init'); } function TemplateClass() {} TemplateClass.prototype = Animal.prototype; Cat.prototype = new TemplateClass(); Cat.prototype.constructor = Cat; Cat.prototype.sleep = function() { alert('Cat sleep'); }; var c2 = new Cat(); // alert Cat init c2.sleep(); // alert Cat sleep a1.sleep(); // alert Animal sleep c2的原型链
  36. 36. 封装类继承函数 var TemplateClass = function() {}, chain = function(object) { TemplateClass.prototype = object; var result = new TemplateClass(); TemplateClass.prototype = null; return result; }; function extend(SubClass, SuperClass, overrides) { var subProto, name; SuperClass = SuperClass || Object; SubClass.prototype = chain(SuperClass.prototype); subProto = SubClass.prototype; subProto.constructor = SubClass; if (overrides) { for (name in overrides) { if (overrides.hasOwnProperty(name)) { subProto[name] = overrides[name]; } } } }
  37. 37. 一个完整的类继承例子(1) function Animal(name, color) { this.name = name; this.color = color; } extend(Animal, Object, { sleep: function() { alert(this.name + ' sleep'); } }); var a1 = new Animal('倒霉熊', 'white'); a1.sleep(); // alert 倒霉熊 sleep function Cat() { Animal.apply(this, arguments); // 通过调用父类的构造函数实现初始化 } extend(Cat, Animal, { greenEye: true, mew: function() { alert(this.name + ' mew'); } }); var c2 = new Cat('没头脑', 'red'); c2.mew(); // alert 没头脑 mew c2.sleep(); // alert 没头脑 sleep alert(c2.greenEye); // true
  38. 38. 一个完整的类继承例子(2) function PersianCat() { Cat.apply(this, arguments); // 通过调用父类的构造函数实现初始化 } extend(PersianCat, Cat, { name: 'persian cat', blueEye: true, mew: function() { Cat.prototype.mew.call(this); // 通过调用父类的mew() alert(this.name + ' miaow'); } }); var p3 = new PersianCat('不高兴', 'yellow'); p3.mew(); // alert 不高兴 mew,alert 不高兴 miaow p3.sleep(); // alert 不高兴 sleep alert(p3.greenEye); // true alert(p3.blueEye); // true
  39. 39. 一个完整的类继承例子(3) a1、c2、p3中的是本地属性,其他的都是prototype属性,从例子的运行结果可以 知道,对本地属性赋值,并不会覆盖prototype属性。 在使用this访问对象的属性或方法时,是先从本地属性中查找,如果未到,那么 它会向上遍历原型链,直到找到给定名称的属性为止,当到达原型链的顶部(也 就是Object.prototype)仍然没有找到指定的属性,就会返回undefined。
  40. 40. hasOwnProperty() 确定某个对象是否具有带指定名称的属性。 对与new操作符返回的对象,它可以用来判断某一个属性到底是本地 属性,还是prototype属性。 如: alert(c2.hasOwnProperty('greenEye')); // false alert(c2.hasOwnProperty('name')); // true alert(Cat.prototype.hasOwnProperty('greenEye')); // true
  41. 41. in运算符 测试一个对象中是否存在一种属性。 它不仅检测本地属性,还会检测原型链中的prototype属性。 如: alert('sleep' in c2); // true alert('greenEye' in c2); // true
  42. 42. isPrototypeOf() 确定一个对象是否存在于另一个对象的原型链中。 如: alert(Cat.prototype.isPrototypeOf(c2)); // true alert(Animal.prototype.isPrototypeOf(c2)); // true
  43. 43. 参考资料 JavaScript: The World's Most Misunderstood Programming Language Prototypal Inheritance in JavaScript Private Members in JavaScript JavaScript Object Layout
  44. 44. 炎燎 手机搜狐 https://github.com/maxzhang http://maxzhang.github.io

×