一、创建对象的方法(6种)

  1.工厂模式

  即用函数来封装以特定接口创建对象的细节。

function createPerson(name,age,job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
}
return o;
}
var person1 = createPerson('Lily',17,'Teacher');
var person2 = createPerson('Simon',22,'Doctor');

  弊端:无法解决对象识别的问题(即怎么知道一个对象的类型)。

  2.构造函数模式

function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
}
}
var person1 = new Person('Lily',17,'Teacher');
var person2 = new Person('Simon',22,'Doctor');

  构造器函数始终都应该以大写字母开头;要创建新的实例,必须使用new操作符。

  与工厂模式的区别:

    A、没有显式地创建对象

    B、直接将属性和方法赋给了this对象

    C、没有return语句

  创建自定义的构造函数意味着将来可以将它的实例标识为一种特定的类型,这正是构造函数胜于工厂模式的地方。

  检测对象类型可使用 instanceof 操作符:

   alert(person1 instanceof Object);//true
alert(person1 instanceof Person);//true
alert(person2 instanceof Object);//true
alert(person2 instanceof Person);//true

  构造函数的弊端: 每个方法都要在每个实例上重新创建一遍。

  在之前的例子中,person1和person2都有一个名为sayName()的方法,但两个方法不是同一个Function的实例。(因为,ECMAScript中的函数是对象,因此每定义一个函数,实际上就是实例化一个对象)从逻辑上讲,此时的构造函数也可以这样定义:

function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = new Function('alert(this.name)');//与声明函数在逻辑上是等价的。
}

 以这种方式创建函数,会导致不同的作用域和标识符解析。

  

  3.原型模式

    function Person(){};
Person.prototype.name = 'Lily';
Person.prototype.age = 17;
Person.prototype.job = 'Teacher';
Person.prototype.sayName = function(){
alert(this.name);
} var person1 = new Person();
alert(person1.sayName);//'Lily' var person2 = new Person();
alert(person2.sayName);//'Lily' alert(person1.sayName == person2.sayName);//true

  

  通过 isPrptotypeOf() 方法可以确定实例与某对象原型之间的关系:

alert(Person.prototype.isPrototypeOf(person1));//true
alert(Person.prototype.isPrototypeOf(person2));//true

  因为person1和person2都有一个指向Person.prototype的的指针,因而都返回了true。

  

  虽然可以通过实例对象访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果在实例中添加了一个属性,而该属性与实例原型中的一个属性同名,那么新创建的属性就会屏蔽原型中的那个属性:

    function Person(){};
Person.prototype.name = 'Lily';
Person.prototype.age = 17;
Person.prototype.job = 'Teacher';
Person.prototype.sayName = function(){
alert(this.name);
} var person1 = new Person();
var person2 = new Person(); person1.name = 'Simon';
alert(person1.name);//'Simon' 来自实例
alert(person2.name);//'Lily'  来自原型

  即,为对象实力添加一个属性时,该属性就会屏蔽原型对象中的同名属性;换句话说,添加这个属性只会阻止我们访问原型中的那个同名属性,而不会修改那个属性。即使将这个属性设置为null,也无法恢复其指向原型的链接。

  想完全删除实例属性,可使用 delete 操作符:

    function Person(){};
Person.prototype.name = 'Lily';
Person.prototype.age = 17;
Person.prototype.job = 'Teacher';
Person.prototype.sayName = function(){
alert(this.name);
} var person1 = new Person();
var person2 = new Person(); person1.name = 'Simon';
alert(person1.name);//'Simon' 来自实例
alert(person2.name);//'Lily'  来自原型 delete person1.name;
alert(person1.name);//'Lily' 来自原型

  

  使用  hasOwnProperty()   方法可以检测一个属性是存在于实例中,还是原型中(存在于实例中则返回true):

   function Person(){};
Person.prototype.name = 'Lily';
Person.prototype.age = 17;
Person.prototype.job = 'Teacher';
Person.prototype.sayName = function(){
alert(this.name);
} var person1 = new Person(); alert(person.hasOwnProperty('name'));//false person1.name = 'Simon';
alert(person.hasOwnProperty('name'));//true

  

  使用 in 操作符能够检测某对象是否具有某个属性(无论该属性是存在于实例中还是原型中):

function Person(){};
Person.prototype.name = 'Lily';
Person.prototype.age = 17;
Person.prototype.job = 'Teacher';
Person.prototype.sayName = function(){
alert(this.name);
} var person1 = new Person(); alert(person.hasOwnProperty('name'));//false
   alert('name' in person1); //true
    person1.name = 'Simon';
alert(person.hasOwnProperty('name'));//true
   alert('name' in person1); //true

  

  故而,检测某属性是否存在于原型中可使用函数↓

   function hasPrototypeProperty(object,name){
return !object.hasOwnProperty(name) && (name in object);
}

  只要in操作符返回true而hasOwnProperty()返回false,即可确定属性是原型中的属性。

  要取得对象上所有可枚举的实例属性,可使用ES5的 object.keys() 方法。该方法接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组: 

   function Person(){};
Person.prototype.name = 'Lily';
Person.prototype.age = 17;
Person.prototype.job = 'Teacher';
Person.prototype.sayName = function(){
alert(this.name);
} var keys = Object.keys(Person.prototype);
alert(keys); //"name,age,job,sayName";
alert(Array.isArray(keys)); //true
alert(keys.length); // var person1 = new Person();
person1.name = "Candy";
person1.job = "Singer";
var keys2 = Object.keys(person1);
alert(keys2); //"name,job";

  

  constructor 属性不可枚举。若想获得所有实例属性(无论是否可枚举),则可使用 Object.getOwnPropertyName()  方法:

    function Person(){};
Person.prototype.name = 'Lily';
Person.prototype.age = 17;
Person.prototype.job = 'Teacher';
Person.prototype.sayName = function(){
alert(this.name);
} var keys = Object.getOwnPropertyName(Person.prototype);
alert(keys); //"constructor,name,age,job,sayName";

  

  将 Person.prototype 设置为等于一个以对象字面量创建的新对象,是更为简单的原型语法:

function Person(){};

    Person.prototype = {
name: 'Lily',
age: 17,
job: 'Teacher',
sayName: function(){
alert(this.name);
}
};

  但这样的语法,本质上是完全重写了默认的 prototype 对象,使得 constructor 属性不再指向Person了(指向Object构造函数)。

  可通过以下方式将constructor属性重新指向Person:

function Person(){};

    Person.prototype = {
constructor: Person, //重设constructor属性
name: 'Lily',
age: 17,
job: 'Teacher',
sayName: function(){
alert(this.name);
}
};

  但这种方式会导致它的[[Enumerable]](可枚举)特性被设置为true。详见高程P155.

  对原型对象所做的任何修改都能立即从实例上反映出来,即便是先创建了实例后修改原型:

   var friend = new Person();

    Person.prototype.sayHi = function(){
alert('Hi!');
}; friend.sayHi(); //"Hi!"

  但若是重写整个原型对象,情况就不一样了:

    var friend = new Person();

    Person.prototype = {
construcor: Person,
name: 'Candy',
age: 22,
job: 'Dancer',
sayName: function(){
alert(this.name);
}
}; friend.sayName(); //error

  因为,调用构造函数时会为实例添加一个指向最初原型的指针,而把原型修改为另外一个对象就等同于切断了实例与最初原型之间的联系。

  实例中的指针仅指向原型,而不指向构造函数。

  重写原型对象切断了现有原型与任何之前已经存在的对象实例之间的联系,他们引用的仍然是最初的原型。

  原型对象的弊端:当属性中包含引用类型值时,修改实例中相应的引用类型值将会间接修改原型中的引用类型值:

function Person(){}
Person.prototype = {
construcor: Person,
name: 'Candy',
age: 22,
job: 'Dancer',
friends: ['Mary','June'],
sayName: function(){
alert(this.name);
}
}; var person1 = new Person();
var person2 = new Person(); person1.friends.push('Van'); alert(person1.friends); //"Mary,June,Van"
alert(person2.friends); //"Mary,June,Van"
alert(person1.friends === person2.friends); //true

  4.组合使用构造函数模式和原型模式

  构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性:

function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ['Lily','Candy'];
} Person.prototype = {
constructor: Person,
sayName: function(){
alert(this.name);
}
} var person1 = new Person('Nicholas',29,'Software Engineer');
var person2 = new Person('Greg',27,'Doctor'); person1.friends.push('Simon');
alert(person1.friends); //"Lily,Candy,Simon"
alert(person2.friends); //"Lily,Candy"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true

  5.动态原型模式

  6.寄生构造函数模式(和工厂模式一样)

  7.稳妥构造函数模式

  稳妥对象:没有公共属性,其方法也不引用this的对象。

  稳妥构造函数遵循与寄生构造函数类似的模式,不同之处在于:新创建的实例方法不引用this;不使用new操作符调用构造函数。 

function Person(name,age,job){
//创建要返回的对象
var o = new Object();
//可以在这里定义私有变量和函数 //添加方法
o.sayName = function(){
alert(name);
};
//返回对象
return o;
} var friend = Person('Nicholas',22,'Software Engineer');
friend.sayName(); //"Nicholas"

二、继承

  1.原型链继承

  基本思想:利用原型让一个引用类型继承另一个引用类型的属性和方法。

  每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。故而,使原型对象等于另一个类型的实例,就实现继承:

A.prototype = new B();    //继承了B

  原型链继承的实质:重写原型对象。

  当以读取模式访问一个实例属性时,首先会在实例中搜索该属性,若没有找到该属性,则会继续搜索实例的原型。在通过原型链继承的情况下,搜索过程就得以沿着原型链继承向上。

  所以引用类型都默认继承了Object,这个继承也是通过原型链实现的。所以函数的1默认原型都是Object的实例。P164

  确定原型和实例之间的关系:使用 instanceofisPrototypeOf() 方法。

alert(A instanceof B);  //boolean  

// A是B的实例,则返回true,反之返回false
alert(A.prototype.isPrototypeOf(B));    //boolean
//A的原型也是B的原型

  给原型添加方法的代码一定要放在替换原型的语句之后。

  在通过原型链实现继承时,不能使用对象字面量创建原型方法,这样会重写原型方法。P166

  原型链继承的弊端:问题源于包含引用类型值的原型,包含引用类型值的原型属性会被所有实例共享。

  

  2.借用构造函数继承

  即,在子类型构造函数的内部调用超类型构造函数,通过 apply() call() 实现:

function Sub(){
Sup.call(this);  //Sub继承了Sup
}

  弊端:方法都在构造函数中定义,函数复用无从说起。

  

  3.组合继承

  将借用构造函数和原型链组合起来。

  思路:通过原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。

  

  4.原型式继承

  5.寄生式继承

  6.寄生组合式继承

  

  还是直接看书更好理解啊朋友们~

《Javascript高级程序设计》第六章笔记整理的更多相关文章

  1. JavaScript高级程序设计 第六章 面向对象程序设计

    面向对象程序设计 ECMA-262将对象定义为:“无序属性的集合,其属性可以包含基本值.对象或者函数.”严格来讲,这就相当于说对象是一组没有特定顺序的值.对象的每个属性和方法都有一个名字,而每个名字都 ...

  2. JavaScript高级程序设计-第六章面向对象的程序设计

    创建对象主要的两种形式,创建Object实例和创建对象字面量 对象包含属性和方法 数据 .属性有四个特性,特性是为了描述属性行为的,他们是: Configurable(可配置的)是否能删除或是否能修改 ...

  3. 《JavaScript高级程序设计》——第二章在HTML使用JavaScript

    这章讲的是JavaScript在HTML中的使用,也就是<script>元素的属性.书中详细讲了async.defer.src和type四个<script>的属性. 下面是对第 ...

  4. JavaScript 高级程序设计 第5章引用类型 笔记

    第五章 引用类型 一.object类型 1.创建方法: 1.使用new 操作符创建 var person=new object() Person.name=”Nicholasa” Porson.age ...

  5. JavaScript高级程序设计第20章JSON 笔记 (学习笔记)

    第二十章 JSON 1.Json 可以表示三种类型的值: 1.简单值: 表示数值:5  表示字符串:“hello wrold”注表示字符串时必须使用双引号 2.对象: {“name”:“mi”,”ag ...

  6. JavaScript高级程序设计第14章表单脚本 (学习笔记)

    第十四章 表单脚本 1.阻止默认表单提交 1.提交表单数据 1.使用type=submit提交按钮 2.使用submit():方法 注意:当用户点击提交按钮时,会触发submit事件,从而在这里我们有 ...

  7. javascript高级程序设计第三章的一些笔记

    [TOC] 1. 语法 1.1 区分大小写 变量.函数名和操作费都区分大小写. 1.2 标识符 标识符指变量.函数.属性的名字,或者函数的参数.标识符按以下规则组合: 第一个字符必须是一个字母,下划线 ...

  8. 读书笔记 - js高级程序设计 - 第六章 面向对象的程序设计

      EcmaScript有两种属性 数据属性 和 访问器属性 数据属性有4个特性 Configurable Enumerable Writable Value   前三个值的默认值都为false   ...

  9. 读书时间《JavaScript高级程序设计》六:事件

    Javascript与HTML之间的交互是通过事件实现的. 1. 事件流 事件流描述的是从页面中接收事件的顺序. <!DOCTYPE html> <html> <head ...

随机推荐

  1. C# winform TreeView中关于checkbox选择的完美类[转]

    http://www.cnblogs.com/kingangWang/archive/2011/08/15/2139119.html public static class TreeViewCheck ...

  2. linux系统调用之文件系统操作

    access 确定文件的可存取性 chdir 改变当前工作目录 fchdir 参见chdir chmod 改变文件方式 fchmod 参见chmod chown 改变文件的属主或用户组 fchown ...

  3. 第一节,windows和ubuntu下深度学习theano环境搭建

    先讲解windows下深度学习环境的搭建 步骤一  安装Anaconda Anaconda是一个用于科学计算的python发行版,支持linux,mac,windows系统,提供了包管理和环境管理的功 ...

  4. 做错的题目——给Array附加属性

  5. POJ 3352 Road Construction ; POJ 3177 Redundant Paths (双联通)

    这两题好像是一样的,就是3177要去掉重边. 但是为什么要去重边呢??????我认为如果有重边的话,应该也要考虑在内才是. 这两题我用了求割边,在去掉割边,用DFS缩点. 有大神说用Tarjan,不过 ...

  6. Android MVP 架构一 View与Presenter

    View:主要负责界面的显示及跟数据无关的逻辑,比如设置控件的点击事件等 Presenter:主要负责View与Model的交互 Model:数据部分 ------- MVP的核心是: View层不持 ...

  7. (二叉树 BFS DFS) leetcode 104. Maximum Depth of Binary Tree

    Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...

  8. 剑指Offer_编程题_10

    题目描述 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形.请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? class Solution { public: int r ...

  9. SQL语法基础之UPDATE语句

    SQL语法基础之UPDATE语句 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.查看UPDATE语句的帮助信息 1>.查看UPDATE的帮助信息 mysql> ? ...

  10. ActiveMQ详细入门使用教程

    ActiveMQ介绍 MQ是消息中间件,是一种在分布式系统中应用程序借以传递消息的媒介,常用的有ActiveMQ,RabbitMQ,kafka.ActiveMQ是Apache下的开源项目,完全支持JM ...