- /*
- * 面向对象的程序设计
- */
- function cl(x) {
- console.log(x);
- }
- //6.1 理解对象
- var person = { //使用对象字面量创建对象
- name: "Jason",
- age: 26,
- job: "Software Engineer",
- sayName: function() {
- cl(this.name);
- }
- };
- //6.1.1 属性类型 defineProperty()
- //6.1.1.1 数据属性
- var person = {};
- Object.defineProperty(person, 'name', {
- writable: false,
- //表示能否修改属性的值
- configurable: false,
- //表示能否通过delete删除属性从而重新定义属性
- enumerable: false,
- //表示能否通过for-in循环返回属性
- value: 'Jason'
- });
- cl(person.name); //=>Jason
- person.name = "Greg";
- cl(person.name); //=>Jason
- delete person.name;
- cl(person.name); //=>Jason
- // 6.1.1.2 访问器属性
- var book = {
- _year: 2014,
- //下划线记号,用于表示只能通过对象方法访问的属性
- edition: 1
- };
- Object.defineProperty(book, "year", {
- get: function() {
- return this._year;
- },
- set: function(newValue) {
- if (newValue > 2014) {
- this._year = newValue;
- this.edition += newValue - 2014;
- }
- }
- });
- book.year = 2015;
- cl(book.edition); //=>2
- //6.1.2 定义多个属性 defineProperties()
- var book = {};
- Object.defineProperties(book, {
- _year: {
- value: 2014
- },
- edition: {
- value: 1
- },
- year: {
- get: function() {
- return this._year;
- }
- },
- set: function(newValue) {
- if (newValue > 2014) {
- this._year = newValue;
- this.edition += newValue - 2014;
- }
- }
- });
- cl(book.edition); //=>1
- // 6.1.3 读取属性的特性
- var descriptor = Object.getOwnPropertyDescriptor(book, "_year"); //取得给定属性的描述符,_year为数据属性
- cl(descriptor.value); //=>2014
- cl(descriptor.configurable); //=>false
- cl(typeof descriptor.get); //=>undefined
- var descriptor = Object.getOwnPropertyDescriptor(book, "year"); //取得给定属性的描述符,year为访问器属性
- cl(descriptor.value); //=>undefined
- cl(descriptor.enumerable); //=>false
- cl(typeof descriptor.get); //=>function
- //6.2 创建对象
- //6.2.1 工厂模式创建对象
- //优缺点:解决了创建多个相似对象的问题,却没有解决对象识别的问题
- function createPerson(name, age, job) {
- var o = new Object();
- o.name = name;
- o.age = age;
- o.job = job;
- o.sayName = function() {
- cl(this.name);
- };
- return o;
- }
- var person1 = createPerson("Jason", 26, "Software Engineer");
- var person2 = createPerson("Greg", 27, "Doctor");
- //6.2.2 构造函数模式创建对象
- function Person(name, age, job) {
- this.name = name;
- this.age = age;
- this.job = job;
- this.sayName = function() {
- cl(this.name);
- }
- }
- var person1 = new Person("Jason", 26, "Software Engineer");
- var person2 = new Person("Greg", 27, "Doctor");
- cl(person1.constructor == Person); //=>true 构造函数属性constructor可用来标识对象类型
- cl(person2 instanceof Person); //=>true instanceof检测对象类型
- // 6.2.2.1将构造函数当做函数
- function Person(name, age, job) {
- this.name = name;
- this.age = age;
- this.job = job;
- this.sayName = function() {
- cl(this.name);
- }
- }
- //当做构造函数使用
- var person = new Person("Jason", 26, "Software Engineer");
- //person.sayName(); //=>"Jason"
- //作为普通函数调用
- Person("Greg", 27, "Doctor"); //添加到window
- window.sayName(); //=>"Greg"
- //在另一对象的作用域中调用
- var o = new Object();
- Person.call(o, "Kristen", 25, "Nurse");
- //o.sayName(); //=>"Kristen"
- // 6.2.2.2构造函数的问题:每个方法都要在实例上重新创建一遍
- function Person(name, age, job) {
- this.name = name;
- this.age = age;
- this.job = job;
- this.sayName = sayName;
- }
- function sayName() {
- cl(this.name);
- }
- //6.2.3 原型模式创建对象
- //使用原型对象的好处是:可以让所有对象实例共享它所包含的属性和方法
- function Person() {};
- Person.prototype.name = "Jason";
- Person.prototype.age = 26;
- Person.prototype.job = "Software Engineer";
- Person.prototype.sayName = function() {
- cl(this.name);
- };
- var person1 = new Person();
- person1.sayName(); //=>"Jason"
- var person2 = new Person();
- person2.sayName(); //=>"Jason"
- cl(person1.sayName == person2.sayName); //=>true
- //6.2.3.1 理解原型对象 //6.2.3.2 原型与in操作符
- cl(Person.prototype.isPrototypeOf(person1)); //=>true 测试实例是否指向原型对象
- cl(Object.getPrototypeOf(person1) == Person.prototype); //=>true 确定返回的对象实际就是这个对象的原型
- cl(Object.getPrototypeOf(person1).name); //=>"Jason" Object.getPrototypeOf()可以方便地取得一个对象的原型
- var person1 = new Person();
- var person2 = new Person();
- cl(person1.hasOwnProperty("name")); //=>false
- cl("name" in person1); //=>true
- person1.name = "Robin";
- cl(person1.name); //=>"Robin"——来自实例
- cl(person2.name); //=>"Jason"——来自原型
- cl(person1.hasOwnProperty("name")); //=>true 属性在实例中返回true
- cl("name" in person1); //=>true
- delete person1.name; //删除实例属性
- cl(person1.name); //=>"Jason"——来自原型
- cl(person1.hasOwnProperty("name")); //=>false 属性存在于实例中才返回true
- //判断属性是原型中的属性
- function hasPrototypeProperty(object, name) {
- return ! object.hasOwnProperty(name) && (name in object);
- }
- cl(hasPrototypeProperty(person, "name")); //=>true
- //Object.keys():接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组
- var keys = Object.keys(Person.prototype);
- cl(keys); //=>["name", "age", "job", "sayName"]
- var p1 = new Person();
- p1.name = "Bob";
- p1.age = 31;
- var p1keys = Object.keys(p1);
- cl(p1keys); //=> ["name", "age"]
- var keys = Object.getOwnPropertyNames(Person.prototype); //=>获取所有实例属性
- cl(keys); //=> ["constructor", "name", "age", "job", "sayName"]
- //6.2.3.3 更简单的原型语法
- function Person() {};
- Person.prototype = {
- name: "Jason",
- age: 26,
- job: "Software Engineer",
- sayName: function() {
- cl(this.name);
- }
- }
- var friend = new Person();
- cl(friend instanceof Person); //=>true
- cl(friend.constructor == Person); //=>false constructor属性不再指向Person函数
- //6.2.3.4 原型的动态性
- var friend = new Person();
- Person.prototype.sayHi = function() {
- cl("hi");
- }
- friend.sayHi(); //=>"hi"
- //调用构造函数时会为实例添加一个指向最初原型的[[prototype]]指针
- //把原型修改为另外一个对象就等于切断了构造函数与最初原型之间的联系
- //请记住:实例中的指针仅指向原型,而不指向构造函数
- //6.2.3.5 原生对象的原型
- //通过原生对象的原型,不仅可以取得所有默认方法的引用,而且也可以定义新方法
- String.prototype.startsWith = function(text) {
- return this.indexOf(text) == 0;
- }
- var msg = "Hello world!";
- cl(msg.startsWith("Hello")); //=>true
- //6.2.3.5 原型对象的问题
- //原型模式创建对象的最大问题是其共享的本性所导致的
- function Person() {}
- Person.prototype = {
- constructor: Person,
- name: "Jason",
- age: 16,
- job: "Software Engineer",
- friends: ["Sandy", "Alex"],
- sayName: function() {
- cl(this.name);
- }
- }
- var person1 = new Person();
- var person2 = new Person();
- person1.friends.push("Van");
- cl(person1.friends); //=>["Sandy", "Alex", "Van"]
- cl(person2.friends); //=>["Sandy", "Alex", "Van"]
- cl(person1.friends == person2.friends); //=>true
- //6.2.4 组合使用构造函数模式和原型模式 (实践中常用)
- //构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性
- function Person2(name, age, job) {
- this.name = name;
- this.age = age;
- this.job = job;
- this.friends = ["Sandy", "Alex"];
- }
- Person.prototype = {
- constructor: Person2,
- sayName: function() {
- cl(this.name);
- }
- }
- var person1 = new Person2("Jason", 26, "Software Engineer");
- var person2 = new Person2("Greg", 27, "Doctor");
- person1.friends.push("Van");
- cl(person1.friends); //=> ["Sandy", "Alex", "Van"]
- cl(person2.friends); //=> ["Sandy", "Alex"]
- cl(person1.sayName == person2.sayName); //=>true
- //6.2.5 动态原型模式
- function Person3(name, age, job) {
- //属性
- this.name = name;
- this.age = age;
- this.job = job;
- //方法
- if (typeof this.sayName != "function") {
- Person3.prototype.sayName = function() {
- cl(this.name);
- };
- }
- }
- var friend = new Person3("Jason", 26, "Software Engineer");
- friend.sayName(); //=>Jason
- //6.2.6 寄生构造函数模式 与工厂模式相似
- function Person4(name, age, job) {
- var o = new Object();
- o.name = name;
- o.age = age;
- o.job = job;
- o.sayName = function() {
- cl(this.name);
- };
- return o;
- }
- var friend = new Person4("Jason", 26, "Software Engineer");
- friend.sayName(); //=>Jason
- cl(friend instanceof Person4); //=>false
- //寄生构造函数模式可以在特殊情况下用来为对象创建构造函数
- function SpecialArray() {
- //创建数组
- var values = new Array();
- //添加值
- values.push.apply(values, arguments);
- //添加方法
- values.toPipedString = function() {
- return this.join("|");
- };
- return values;
- }
- var colors = new SpecialArray("red", "blue", "green");
- cl(colors.toPipedString()); //=>"red|blue|green"
- //6.2.7 稳妥构造函数模式:适合在某些安全执行环境
- function Person5(name, age, job) {
- //创建要返回的对象
- var o = new Object();
- //定义私有变量和函数
- o.name = name;
- o.age = age;
- o.job = job;
- //添加方法
- o.sayName = function() {
- cl(this.name);
- };
- //返回对象
- return o;
- }
- var friend = Person5("Jason", 26, "Software Engineer");
- friend.sayName(); //Jason
- //6.3 继承
- //ECMAScript只支持实现继承,主要是依靠原型链来实现的
- //6.3.1 原型链
- function SuperType() {
- this.prototype = true;
- };
- SuperType.prototype.getSuperValue = function() {
- return this.prototype;
- };
- function SubType() {
- this.subproperty = false;
- }
- //继承了 SuperType
- SubType.prototype = new SuperType();
- //添加新方法
- SubType.prototype.getSubValue = function() {
- return this.subproperty;
- };
- //重写父类型中的方法
- SubType.prototype.getSuperValue = function() {
- return false;
- }
- var instance = new SubType();
- //instance指向SubType的原型,SubType的原型又指向SuperType的原型
- cl(instance.getSuperValue()); //=>false
- /**
- * instance.getSuperValue()会经历三个搜索步骤:
- * 1)搜索实例
- * 2)搜索SubType.prototype;
- * 3)搜索SuperType.prototype。
- */
- //6.3.1.1 别忘记默认的原型:所有引用类型默认继承了Object
- //6.3.1.2 确定原型和实例的关系
- cl(instance instanceof Object); //=>true
- cl(instance instanceof SuperType); //=>true
- cl(instance instanceof SubType); //=>true
- cl(Object.prototype.isPrototypeOf(instance)); //=>true
- cl(SuperType.prototype.isPrototypeOf(instance)); //=>true
- cl(SubType.prototype.isPrototypeOf(instance)); //=>true
- //6.3.1.3 谨慎地定义方法
- //通过原型链实现继承时,不能使用对象字面量创建原型方法
- //6.3.1.4 原型链的问题:最主要的问题来自包含引用类型值的原型;
- function SuperType2() {
- this.colors = ['red', 'blue', 'green'];
- };
- function SubType2() {};
- //继承了SuperType2
- SubType2.prototype = new SuperType2();
- var instance1 = new SubType2();
- instance1.colors.push('black');
- cl(instance1.colors); //=> ["red", "blue", "green", "black"]
- var instance2 = new SubType2();
- cl(instance2.colors); //=> ["red", "blue", "green", "black"]
- //原型链的第二个问题是:创建子类型的实例时,不能向父类型的构造函数中传递参数
- //6.3.2 借用构造函数(也叫伪造对象或经典继承):在子类型构造函数的内部调用父类型构造函数
- function SuperType3() {
- this.colors = ['red', 'blue', 'green'];
- }
- function SubType3() {
- //继承了SuperType3
- SuperType3.call(this);
- }
- var instance3 = new SubType3();
- instance3.colors.push("black");
- cl(instance3.colors); //=>["red", "blue", "green", "black"]
- var instance4 = new SubType3();
- cl(instance4.colors); //=>["red", "blue", "green"]
- //6.3.2.1 传递参数:即可以在子类型构造函数中向父类型构造函数传递参数
- function SuperType5(name) {
- this.name = name;
- }
- function SubType5() {
- //继承了SuperType5,同时还传递了参数
- SuperType5.call(this, "Jason");
- //实例属性
- this.age = 25;
- }
- var instance5 = new SubType5();
- cl(instance5.name); //=>"Jason"
- cl(instance5.age); //=>25
- // 6.3.2.2 借用构造函数的问题:方法都在构造函数中定义,因此函数复用就无从谈起。所有类型都只能使用构造函数模式。
- //6.3.3 组合继承(也叫伪经典继承),实践中常用的继承模式
- function SuperType6(name) {
- this.name = name;
- this.colors = ['red', 'blue', 'green'];
- }
- SuperType6.prototype.sayName = function() {
- cl(this.name);
- };
- function SubType6(name, age) {
- //借用构造函数继承属性
- SuperType6.call(this, name);
- //定义私有属性
- this.age = age;
- }
- //使用原型链继承方法
- SubType6.prototype = new SuperType6();
- //定义私有方法
- SubType6.prototype.sayAge = function() {
- cl(this.age);
- };
- var instance6 = new SubType6('Jason', 26);
- instance6.colors.push('black');
- cl(instance6.colors); //=>["red", "blue", "green", "black"]
- instance6.sayName(); //=>Jason
- instance6.sayAge(); //=>26
- var instance7 = new SubType6('Greg', 27);
- cl(instance7.colors); //=>["red", "blue", "green"]
- instance7.sayName(); //=>"Greg"
- instance7.sayAge(); //=>27
- //6.3.4 原型式继承 Object.create()方法
- //6.3.5 寄生式继承
- //6.3.6 寄生组合式继承:只调用一次父类型构造函数,提高效率
- function inheritPrototype(subType, superType) {
- var prototype = Object.create(superType.prototype); //创建对象
- prototype.constructor = subType; //增强对象
- subType.prototype = prototype; //指定对象
- }
- function SuperType7(name) {
- this.name = name;
- this.colors = ['red', 'blue', 'green'];
- }
- SuperType7.prototype.sayName = function() {
- cl(this.name);
- }
- function SubType7(name, age) {
- //借用构造函数继承属性
- SuperType7.call(this, name);
- //定义私有属性
- this.age = age;
- }
- //寄生式继承方法
- inheritPrototype(SubType7, SuperType7);
- //定义私有方法
- SubType7.prototype.sayAge = function() {
- cl(this.age);
- }
- var instance8 = new SubType7('Jason', 26);
- instance8.colors.push('black');
- cl(instance8.colors); //=>["red", "blue", "green", "black"]
- instance8.sayName(); //=>Jason
- instance8.sayAge(); //=>26
来源: http://lib.csdn.net/snippet/javascript/43435