在不会面向对象编程之前,我们都是采用面向过程编程的。按照传统流程编写一个个的函数来解决需求的这种方式就是过程编程。
面向对象编程就是将你的需求抽象成一个对象,然后针对这个对象分析其特征(属性)与动作(方法)。而这个对象我们就称之为 类。
封装
在javascript中创建一个类很容易,首先按声明一个函数,保存在一个变量中,按照编程的习惯,我们一般将类的名字的首字母大写。然后在这个函数(类)的内部通过this(函数内部自带的一个变量,用于指向当前这个对象)变量添加属性或者方法来实现,对类添加属性和方法。例如:
var Book = function(id, bookname, price) {
this.id = id;
this.bookname = bookname;
this.price = price;
}
也可以通过类的原型(类也是对象,所i也有原型prototype)上田间属性都和方法。添加属性和方法的方式有两种
- 一种是意义为原型对象属性赋值。
- 另一种是将一个对象赋值给类的原型对象。
Book.prototype.display = function() {
// 展示这本书
};
或者
Book.prototype = {
display: function() {
}
}
注意:
这两种方式不能混用。
我们将所需要的方法和属性都封装在我们抽象的Book类里面,当使用功能方法的时候,就不能直接使用这个Book类,需要使用 new关键字,来实例化(创建)新的对象。实例化后便可通过点语法来访问实例化对象的属性和方法。
var book = new Book(1, 'xxx', 50);
console.log(book.bookname);
问题:通过this添加的属性和方法,和在prototype中添加的属性和方法有什么区别那?
通过this添加的属性和方法是在当前对象上添加的。然后js是一种基于原型prototype的语言,所以创建一个对象的时候,它都有一个原型对象prototype用于指向其继承的属性、方法。这样通过prtotype继承的方法并不是对象自身的。所以使用这些方法的时候,需要通过prototype一级一级查找来得到。当我们创建新的对象的时候,这些方法是不会再创建的。
而this创建是属于对象自身的。我们创建对象的时候,相当于执行了一个类,因此类里面的方法肯定会复制一份。
我的理解:
prototye是每创建一个对象,这个对象都有一个prototype执行对象的原型,也就是实例化这个对象的那个类。因此所有通过prototype创建的属性或者方法,都是绑定在类上的。
this是对象内部的,指向对象自己。因此通过this创建的方法,都是绑定在对象上的,都在对象内部,加之我们创建对象的时候。new xxx();相当于执行了这个类,创建一个新的对象,那对象的属性和方法,也会被重新复制一份。
所以每实例化一个对象,都相当于创造出了一个新的对象(类也属于对象),属于自身的东西肯定会带走,虽然实例化了类,但是类本身还存在的,通过这个类实例化的对象的原型都是指向这个类的。原型上属于类的方法是实例化不走的。因此实例化的时候,原型上的方法是不会被复制的。
但是,因为他们的原型对象都执行同一个类,因此通过this是可以直接调到这些通过prototype创建的属性和方法的。这里通过this调用prototype绑定的方式的流程是一级一级的查找得到的,怎么说那,对象要调用,手的的找到它原型的类吧,然后再调类上的方法吧,至少的这样一级级的找吧。
属性与方法的封装
这里可以以一个例子来深入理解:
比如一个明星,为了再社会中保持一个良好的形象。它就会将一些隐私藏在心里。然后谈的家人人事它,所以会了解一些关于她的事情。外界人不认识她,即使外界人想通过某种途径认识她,也仅仅裂解她暴露出来的事情,不回来接他的隐私。
如果想了解更多关于他的事情怎么办?
我们可以通过她的家人了解她。但是在明星深处自己内心深处的隐私永远不会被别人知道。
在javascript中的实现
声明在函数内部的变量和方法,函数外是访问不到的。通过这个特性我们可以创建私有变量和私有方法。
然后通过this创建的属性和方法,在类创建对象的时候,每个对象自身都会拥有一份,并且这些可以在外部访问到的。因此通过this创建的属性和方法便是共有属性和共有方法。
注意:
1、通过this创建的方法,不但可以访问这些对象的共有方法和共有属性,而且还能访问类或对象的私有属性和私有方法,因此我们也就这种方法为特权方法。
2、我们可以通过特权方法初始化实例对象的一些属性,因此这些在创建对象时调用的特权方法还可以看作是类的 构造器。
var Book = function(id, bookname, 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);
}
创建对象的安全模式
刚学习对象编程的时候,经常在创建对象的时候忘记使用关关键字 new。如果忘记写了,那有没办法处理这种情况,做到即使内使用new也能正确实例化对象?
有找个检察长。
var Book = function(id, bookname, price) {
this.id = id;
this.bookname = bookname;
this.price = price;
}
// 实例化一本书
var book = Book(1, "xxx", 50);
console.log(book);
这段代码很容易让人混淆,认为会打印出Book实例化的对象,但是结果却是:
undefined
仔细看看发现少了一个 new。
看看大神们的测试代码:
console.log(window.id); console.log(window.bookname); console.log(window.price);
结果:
1 xxx 50
我们实例化对象的时候,new可以看作当前对象的this不停的赋值,然后例子中没有new;所以就会直接执行这个函数,而这个函数是在全局作用域中执行的。所以在全局作用域中执行,那this肯定是指向当前对象。自然就是全局变量。而此时的全局变量就是window,所以添加的属性,自然会被添加到window上。而代码中的book变量将是获取Book这个类执行的结果,由于Book类中么有return返回值。自然book就每东西获取,所以结果是undefined(未定义)。
问题:那该怎么避免那?
开启安全模式。
var Book = function(id, bookname, price) {
// 判断执行过程中 this 是否是当前这个对象,如果是说用使用了 new
if(this instanceof Book) {
this.id = id;
this.bookname = bookname;
this.price = price;
}else {
// 否则创建这个对象
return new Book(1, "xxx", 50);
}
}
测试:
// 实例化一本书 var book = Book(1, "xxx", 50); console.log(book.id); console.log(book.bookname); console.log(book.price); console.log(window.id); console.log(window.bookname); console.log(window.price);
结果:
1 xxx 50 undefined undefined undefined
这样就不担心少些 new,导致出错。
