接上一篇

面向对象编程的理解?

答:面向对象编程,就是将你的需求抽象成一个对象,然后针对这个对象分析其特征(属性)与动作(方法)。这个对象我们称之为类。面向对象编程思想其中一个特点就是封装,就是把你需要的功能放在一个对象里。

一、封装

1.1创建一个类

在javascript中创建一个类,很容易,

方法一:首先,声明一个函数保存在变量里,然后,在这个函数内部通过this(函数内部自带的一个变量,用于指向当前这个对象)变量添加属性或者方法,来实现对类的添加属性或方法。

举个例子:

var Book = function(id,bookname,price){
this.id = id;
this.bookname = bookname;
this.price = price;
}

方法二:可以通过类的原型添加属性或方法,有两种方法,不要混用

(1)为原型对象属性赋值的方法

Book.prototype.display = function(){
//展示这本书
};

(2)将对象赋值给类的原型对象

Book.prototype = {
display:function(){}
};

我们需要的方法和属性都封装在我们抽象的Book类里,当使用功能方法时,我们不能直接使用这个Book类,需要用关键字new来实例化新的对象。使用实例化对象的属性或者方法时,可以通过点语法来访问

var book = new Book(10,'javascript课本',50);
console.log(book.bookname);

由于JavaScript的函数级作用域,声明在函数内部的变量以及方法在外界是访问不到的,通过此特性即可创建类的私有变量以及私有方法。然而在函数内部通过this创建的属性和方法,在类创建对象时时,每一个对象自身都拥有一份并且可以外部访问的。因此通过this创建,不但可以访问这些对象的共有属性与共有方法,而且还可以访问到类或者对象自身的私有属性和私有方法。

//私有属性,私有方法;特权方法,对象公有属性,对象公有方法;构造器
var Book = function(id,name,price){
//私有属性
var num = 1;
//私有方法
function checkId(){}; //特权方法
this.getName = function(){};
this.getPrice = function(){};
this.setName = function(){};
this.setPrice = function(){}; //对象公有属性
this.id = id;
//对象公有方法
this.copy = function(){}; //构造器
this.setName(name);
this.setPrice(price);
};

使用原生的prototype对象。

//静态类公有属性(对象不能访问)
Book.isChinese = true; //类静态公有方法(对象不能访问)
Book.resetTime = function(){
console.log('new time');
}; Book.prototype = {
//公有属性
isJSBook:false,
//公有方法
display:function(){}
}

通过new关键字创建的对象时对新对象this的不断赋值,并将prototype指向类的prototype所指向的对象,而类的构造函数外面通过点语法定义的属性方法是不会添加到新创建的对象上去的。

var b = new Book(11,'JavaScript设计',50);
console.log(b.num); //undefined
console.log(b.isJSBook); //false
console.log(b.id); //11
console.log(b.isChinese); //undefined

类的私有属性num,以及静态公有属性isChinese在新创建的b对象里访问不到。而类的公有属性isJSBook在b对象中却可以通过点语法访问到。

但是类的静态公有属性isChinese可以通过类的自身访问。

console.log(Book.isChinese);   //true
Book.resetTime(); //new time

1.2闭包实现

你对闭包的理解?

答:闭包是有权访问另外一个函数作用域中变量的函数,即在一个函数内部创建另外一个函数。我们将这个闭包作为创建对象的构造函数,这样它既是闭包又是可实例化对象的函数,即可访问到类函数作用域的变量,这个变量叫静态私有变量,静态私有方法。

二、继承

总结类: 发现每一个类都有3个部分:

1、第一部分是构造函数内的,供实例化对象复制用的;

2、第二部分是构造函数外的,直接通过点语法添加的,这是供类使用的,实例化对象时访问不到的;

3、第三部分是类的原型中的,实例化对象可以通过其原型链间接的访问到,也是为供所有的实例化对象所共有的。

JavaScript中没有继承这一个现有的机制,该如何实现呢?

(一)子类的原型对象--类式继承

比如:常见的类式继承

//类式继承
//声明父类
function SuperClass(){
this.superValue = true;
}
//为父类添加共有方法
SuperClass.prototype.getSuperValue = function(){
return this.superValue;
}; //声明子类
function SubClass(){
this.subValue = false;
} //继承父类
SubClass.prototype = new SuperClass(); //为子类添加共有方法
SubClass.prototype.getSubValue = function(){
return this.subValue;
}

刚才封装,对比,继承里面声明了2个类,而且第二个类的原型prototype被赋予第一个类的实例。

类式继承需要将第一个类的实例赋值给第二个类的原型。

继承原理:新创建的对象不仅仅可以访问父类原型上的属性和方法,同样可以访问从父类构造函数中复制的属性和方法。将这个对象赋值给子类的原型,那么这个子类的原型同样可以访问父类原型上的属性和方法与从父类构造函数中复制的属性和方法。

var instance = new SubClass();
console.log(instance.getSuperValue()); //true
console.log(instance.getSubValue()); //false

在js中,有一个关键字instanceof 来判断某一个对象是否为某一个类的实例,或者说某一个对象是否继承了某个类,这样可以判断对象和类之间的关系

instanceof如何知道对象和类之间的继承关系呢?

答;instanceof是通过判断对象的prototype链来确定这个对象是否是某一个类的实例,而不关心对象与类的自身结构。

console.log(instance instanceof SuperClass);   //true
console.log(instance instanceof SubClass);   //true
console.log(SubClass instanceof SuperClass);  //false

为啥最后是false,SubClass继承SuperClass,为啥还是false;记住:instanceof是判断前面的对象是否是后边类(对象)的实例,它并不是表示两者的继承。

console.log(SubClass.prototype instanceof SuperClass); //true

类式继承的一个特点:你所创建的所有的对象都是谁的实例?

Object,正式JavaScript为我们提供的原生对象Object。创建的所有的对象都是Object的实例。

console.log(instance instanceof Object); //true

类式继承有两个缺点:

1、由于子类是通过其原型prototype对父类实例化,继承了父类。所以说父类中共有属性要是引用类型,就会在子类中被所有实例共用,因此一个子类的实例更改子类原型从父类构造函数中继承来的共有属性就会直接影响到其他子类。

2、由于子类实现的继承是靠原型的prototype对父类的实例化实现的,因此在创建父类的时候,是无法向父类传递参数的,因而在实例化父类的时候也无法对父类构造函数内的属性进行初始化。

(二)创造即继承--构造函数继承

除了类式继承以外还有构造函数继承

//构造函数式继承
//声明父类
function SuperClass(id){
//引用类型共有属性
this.books = ['JavaScript','html','css'];
//值类型共有属性
this.id = id;
} //父类声明原型的方法
SuperClass.prototype.showBooks = function(){
console.log(this.books);
} //声明子类
function SubClass(id){
//继承父类
SuperClass.call(this,id);
} //创建第一个子类的实例
var instance1 = new SubClass(10);
//创建第二个子类的实例
var instance2 = new SubClass(11); instance1.books.push('设计模式');
console.log(instance1.books); //["JavaScript", "html", "css", "设计模式"]
console.log(instance1.id);   //10
console.log(instance2.books);  //["JavaScript", "html", "css"]
console.log(instance2.id);    //11

注意:SuperClass.call(this.id);这个语句是构造函数式继承的精华,由于call这个方法可以更改函数的作用域

由于这种类型的继承没有涉及到原型prototype,所以父类的原型方法自然就不会被子类继承,而如果想被子类继承就必须放在构造函数中,这样创造出来的每一个实例都会拥有一份而不能共用,这样就违背了代码复用的原则。

综上这两种模式优点,后来就有了组合式的继承

(三)集合优点--组合继承

总结一下:

(1)类式继承,通过子类的原型prototype对父类实例化来实现的

(2)构造函数继承,通过子类的构造函数作用环境执行一下父类的构造函数来实现的

//组合式的继承
//声明父类
function SuperClass(name){
//值类型共有属性
this.name = name;
//引用类型共有属性
this.books = ['html','css','JavaScript'];
}; //父类原型共有方法
SuperClass.prototype.getName = function(){
console.log(this.name);
}; //声明子类
function SubClass(name,time){
//构造函数式继承父类name属性
SuperClass.call(this,name);
//子类中新增共有属性
this.time = time;
} //类式继承 子类原型继承父类
SubClass.prototype = new SuperClass();
//子类原型方法
SubClass.prototype.getTime = function(){
console.log(this.time);
}

组合模式:在子类构造函数中执行父类构造函数,在子类原型上实例化父类。

这样就融合了类式继承和构造函数继承的优点。

var instance1 = new SubClass('js book',2014);
instance1.books.push('设计模式');
console.log(instance1.books); //["html", "css", "JavaScript", "设计模式"]
instance1.getName(); //js book
instance1.getTime(); //2014 var instance2 = new SubClass('css book',2013);
console.log(instance2.books); //["html", "css", "JavaScript"]
instance2.getName(); //css book
instance2.getTime(); //2013

子类的实例中更改父类继承下来的引用类型属性如books,根本就不会影响到其他实例。

但是我们在使用构造函数继承时执行了一遍父类的构造函数,而在实现子类原型的类式继承时又调用了一遍父类的构造器。因此父类构造函数调用了两遍,还不是最完美的方式。

(四)洁净的继承者--原型式继承

借助原型的prototype可以根据已有的对象创建一个新对象,同时不必创建新的自定义对象类型。

var inheritObject(item){
//声明一个过渡函数对象
function F(){};
//过渡对象的原型继承父对象
F.prototype = item;
//返回过渡对象的一个实例,该实例的原型继承了父对象
return new F();
}

他是对类式继承的一个封装,其实其中的过渡对象就相当于类式继承中的子类,只不过在原型式中作为一个过渡对象出现,目的是为了创建要返回新的实例化对象。

当然如果你感觉有必要可以将F过渡缓存起来,不必每次都创建一个新过渡类F,随后就出现了Object.create()的方法。

var book = {
name: 'js book',
alikeBook: ['css book','html book'],
}; var newBook = inheritObject(book);
newBook.name = 'ajax book';
newBook.alikeBook.push('xml book'); var otherBook = inheritObject(book);
otherBook.name = 'flash book';
otherBook.alikeBook.push('as book'); console.log(newBook.name); //ajax book
console.log(newBook.alikeBook); //['css book','html book','xml book','as book'] console.log(otherBook.name); //flash book
console.log(otherBook.alikeBook); //['css book','html book','xml book','as book'] console.log(book.name); //js book
console.log(book.alikebook); //['css book','html book','xml book','as book']

跟类式继承一样,父类对象book中的值类型的属性被复制,引用类型的属性被共用。

javaScript设计模式之面向对象编程(object-oriented programming,OOP)(二)的更多相关文章

  1. javaScript设计模式之面向对象编程(object-oriented programming,OOP)(一)

    面试的时候,总会被问到,你对javascript面向对象的理解? 面向对象编程(object-oriented programming,OOP)是一种程序设计范型.它讲对象作为程序的设计基本单元,讲程 ...

  2. python, 面向对象编程Object Oriented Programming(OOP)

    把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行.为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数 ...

  3. javaScript设计模式之面向对象编程(object-oriented programming,OOP)--寄生组合式继承

    组合式继承:将类式继承同构造函数继承组合使用,但是存在一个问题,子类不是父类的实例,而子类的原型式父类的实例,所以才有了寄生组合式继承. 意思就是说,寄生就是寄生式继承,寄生式继承就是依托于原型继承, ...

  4. Python学习札记(三十) 面向对象编程 Object Oriented Program 1

    参考:OOP NOTE 1.面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. ...

  5. Python学习札记(四十) 面向对象编程 Object Oriented Program 11

    参考:使用元类 NOTE: type() 1.type()函数可以用于检查一个类或者变量的类型. #!/usr/bin/env python3 class Myclass(object): " ...

  6. Python学习札记(三十八) 面向对象编程 Object Oriented Program 9

    参考:多重继承 NOTE #!/usr/bin/env python3 class Animal(object): def __init__(self, name): self.name = name ...

  7. Python学习札记(三十七) 面向对象编程 Object Oriented Program 8 @property

    参考:@property NOTE 1.在绑定参数时,为了避免对属性不符合逻辑的操作,需要对传入的参数进行审核. #!/usr/bin/env python3 class MyClass(object ...

  8. Python学习札记(三十六) 面向对象编程 Object Oriented Program 7 __slots__

    参考:slots NOTE 1.动态语言灵活绑定属性及方法. #!/usr/bin/env python3 class MyClass(object): def __init__(self): pas ...

  9. Python学习札记(三十五) 面向对象编程 Object Oriented Program 6

    参考:实例属性和类属性 NOTE Python是动态语言,根据类创建的实例可以任意绑定属性. class Student(object): def __init__(self, name): self ...

随机推荐

  1. 9.app后端选择什么服务器

    对于很多刚入行的朋友来说,不清楚应该选择什么样的服务器提供商,是选择传统的IDC, 租用服务器租用机柜,还是选择现在很火的云服务器呢?在本文中,通过对比传统的IDC和云服务,简单阐述一下服务器的选择. ...

  2. yii2.0 集成/引入第三方sdk

    首先下载自己要使用的sdk包放到vendor文件夹下面:我以接入ping++为例子如下: 然后在入口文件出引入文件的配置文件: 下面就是在控制器使用了: 下面就可以根据自己要使用的的文件以及方法正常调 ...

  3. nodejs 简单安装环境

    学习资料 1.深入浅出Node.js 2.Node.js开发指南 简介(只捡了我觉得重要的) Node.js是让Javascript脱离浏览器运行在服务器的一个平台,不是语言: Node.js采用的J ...

  4. context.go

    package nsqd type context struct {     nsqd *NSQD }

  5. 【BZOJ 3534】: [Sdoi2014]重建

    题目大意:(略) 题解: 相对误差……我好方. 考虑答案应该为所有合法答案概率之和.对于一个合法的生成树,其出现概率应为所有选取边的概率出现的积 乘以 所有未选取边不出现概率的积. 即: $\;\pr ...

  6. bzoj 4173 打表???

    没有任何思路,打表发现ans=phi(n)*phi(m)*n*m %%% popoqqq Orz 然而并没有看懂-- #include<cstdio> #include<cstrin ...

  7. Python Django 1.Hello Django

    #安装Djangopip install Django #==版本号#选择路径:D:#任意文件夹名 cd Django #罗列Django所提供的命令,其中startproject命令来创建项目 dj ...

  8. python strip()函数和Split函数的用法总结

    strip函数原型 声明:s为字符串,rm为要删除的字符序列. 只能删除开头或是结尾的字符或是字符串.不能删除中间的字符或是字符串. s.strip(rm) 删除s字符串中开头.结尾处,位于 rm删除 ...

  9. java基础常见面试题,这是一篇超长的随笔!!!

    1. Java基础部分....................................................... 4 1.一个".java"源文件中是否可以包括 ...

  10. MySQL 上手教程

    安装 通过官网选择版本下载安装.Mac 上可通过 Homebrew 方便地安装: $ brew install mysql 检查安装是否成功: $ mysql --version mysql Ver ...