js面向对象理解
js面向对象理解
ECMAScript 有两种开发模式:1.函数式(过程化),2.面向对象(OOP)。面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。但是,ECMAScript 没有类的概念,因此它的对象也与基于类的语言中的对象有所不同。
js(如果没有作特殊说明,本文中的js仅包含ES5以内的内容)本身是没有class类型的,但是每个函数都有一个prototype属性。prototype指向一个对象,当函数作为构造函数时,prototype则起到类似class的作用。
一.创建对象
创建一个对象,然后给这个对象新建属性和方法。
var box = new Object(); //创建一个Object 对象
box.name = 'Lee'; //创建一个name 属性并赋值
box.age = 100; //创建一个age 属性并赋值
box.run = function () { //创建一个run()方法并返回值
return this.name + this.age + '运行中...';
};
alert(box.run()); //输出属性和方法的值
上面创建了一个对象,并且创建属性和方法,在run()方法里的this,就是代表box 对象本身。这种是JavaScript 创建对象最基本的方法,但有个缺点,想创建多个类似的对象,就会产生大量的代码。
为了解决多个类似对象声明的问题,我们可以使用一种叫做工厂模式的方法,这种方法就是为了解决实例化对象产生大量重复的问题。
function createObject(name, age) { //集中实例化的函数
var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function () {
return this.name + this.age + '运行中...';
};
return obj;
}
var box1 = createObject('Lee', 100); //第一个实例
var box2 = createObject('Jack', 200); //第二个实例
alert(box1.run());
alert(box2.run()); //保持独立
工厂模式解决了重复实例化的问题,但是它有许多问题,创建不同对象其中属性和方法都会重复建立,消耗内存;还有函数识别问题等等。
二.构造函数的方法
构造函数的方法有一些规范:
1)函数名和实例化构造名相同且大写,(PS:非强制,但这么写有助于区分构造函数和
普通函数);
2)通过构造函数创建对象,必须使用new 运算符。
function Box(name, age) { //构造函数模式
this.name = name;
this.age = age;
this.run = function () {
return this.name + this.age + '运行中...';
};
}
var box1 = new Box('Lee', 100); //new Box()即可
var box2 = new Box('Jack', 200);
alert(box1.run());
alert(box1 instanceof Box); //很清晰的识别他从属于Box
构造函数可以创建对象执行的过程:
1)当使用了构造函数,并且new 构造函数(),那么就后台执行了new Object();
2)将构造函数的作用域给新对象,(即new Object()创建出的对象),而函数体内的this 就
代表new Object()出来的对象。
3)执行构造函数内的代码;
4)返回新对象(后台直接返回)。
注:
1)构造函数和普通函数的唯一区别,就是他们调用的方式不同。只不过,构造函数也是函数,必须用new 运算符来调用,否则就是普通函数。
2)this就是代表当前作用域对象的引用。如果在全局范围this 就代表window 对象,如果在构造函数体内,就代表当前的构造函数所声明的对象。
这种方法解决了函数识别问题,但消耗内存问题没有解决。同时又带来了一个新的问题,全局中的this 在对象调用的时候是Box 本身,而当作普通函数调用的时候,this 又代表window。即this作用域的问题。
三.原型
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法。逻辑上可以这么理解:prototype 通过调用构造函数而创建的那个对象的原型对象。使用原型的好处可以让所有对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息添加到原型中。
function Box() {} //声明一个构造函数
Box.prototype.name = 'Lee'; //在原型里添加属性
Box.prototype.age = 100;
Box.prototype.run = function () { //在原型里添加方法
return this.name + this.age + '运行中...';
};
构造函数的声明方式和原型模式的声明方式存储情况如下:
所以,它解决了消耗内存问题。当然它也可以解决this作用域等问题。
我们经常把属性(一些在实例化对象时属性值改变的),定义在构造函数内;把公用的方法添加在原型上面,也就是混合方式构造对象(构造方法+原型方式):
var person = function(name){
this.name = name
};
person.prototype.getName = function(){
return this.name;
}
var zjh = new person(‘zhangjiahao’);
zjh.getName(); //zhangjiahao
下面详细介绍原型:
1.原型对象
每个javascript对象都有一个原型对象,这个对象在不同的解释器下的实现不同。比如在firefox下,每个对象都有一个隐藏的__proto__属性,这个属性就是“原型对象”的引用。
2.原型链
由于原型对象本身也是对象,根据上边的定义,它也有自己的原型,而它自己的原型对象又可以有自己的原型,这样就组成了一条链,这个就是原型链,JavaScritp引擎在访问对象的属性时,如果在对象本身中没有找到,则会去原型链中查找,如果找到,直接返回值,如果整个链都遍历且没有找到属性,则返回undefined.原型链一般实现为一个链表,这样就可以按照一定的顺序来查找。
1)__proto__和prototype
JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype。以上面的例子为例:
console.log(zjh.__proto__ === person.prototype) //true
同样,person.prototype对象也有__proto__属性,它指向创建它的函数对象(Object)的prototype
console.log(person.prototype.__proto__ === Object.prototype) //true
继续,Object.prototype对象也有__proto__属性,但它比较特殊,为null
console.log(Object.prototype.__proto__) //null
我们把这个有__proto__串起来的直到Object.prototype.__proto__为null的链叫做原型链。如下图:
2)constructor
原型对象prototype中都有个预定义的constructor属性,用来引用它的函数对象。这是一种循环引用
person.prototype.constructor === person //true
Function.prototype.constructor === Function //true
Object.prototype.constructor === Object //true
3)为加深对理解,我们再举一个例子:
function Task(id){
this.id = id;
} Task.prototype.status = "STOPPED";
Task.prototype.execute = function(args){
return "execute task_"+this.id+"["+this.status+"]:"+args;
} var task1 = new Task(1);
var task2 = new Task(2); task1.status = "ACTIVE";
task2.status = "STARTING"; print(task1.execute("task1"));
print(task2.execute("task2"));
结果:
execute task_1[ACTIVE]:task1
execute task_2[STARTING]:task2
构造器会自动为task1,task2两个对象设置原型对象Task.prototype,这个对象被Task(在此最为构造器)的prototype属性引用,参看下图中的箭头指向。
由于Task本身仍旧是函数,因此其”__proto__”属性为Function.prototype, 而内建的函数原型对象的”__proto__”属性则为Object.prototype对象。最后Obejct.prototype的”__proto__”值为null。
总结:
实例对象的__proto__指向,其构造函数的原型;构造函数原型的constructor指向对应的构造函数。构造函数的prototype获得构造函数的原型。
有时某种原因constructor指向有问题,可以通过
constructor:构造函数名;//constructor : Task
重新指向。
四.继承
继承是面向对象中一个比较核心的概念。其他正统面向对象语言都会用两种方式实现继承:一个是接口实现,一个是继承。而ECMAScript 只支持继承,不支持接口实现,而实现继承的方式依靠原型链完成。
在JavaScript 里,被继承的函数称为超类型(父类,基类也行,其他语言叫法),继承的函数称为子类型(子类,派生类)
1.call+遍历
属性使用对象冒充(call)(实质上是改变了this指针的指向)继承基类,方法用遍历基类原型。
function A()
{
this.abc=12;
} A.prototype.show=function ()
{
alert(this.abc);
}; //继承A
function B()
{
//继承属性;this->new B()
A.call(this); //有参数可以传参数A.call(this,name,age)
} //继承方法;B.prototype=A.prototype;
for(var i in A.prototype)
{
B.prototype[i]=A.prototype[i];
}
//添加自己的方法
B.prototype.fn=function ()
{
alert('abc');
}; var objB=new B();
var objA=new A();objB.show();
可以实现多继承。
2.寄生组合继承
主要是Desk.prototype = new Box(); Desk 继承了Box,通过原型,形成链条。主要通过临时中转函数和寄生函数实现。
临时中转函数:基于已有的对象创建新对象,同时还不必因此创建自定义类型
寄生函数:目的是为了封装创建对象的过程
//临时中转函数
function obj(o) { //o表示将要传递进入的一个对象
function F() {} //F构造是一个临时新建的对象,用来存储传递过来的对象
F.prototype = o; //将o对象实例赋值给F构造的原型对象
return new F(); //最后返回这个得到传递过来对象的对象实例
}
//寄生函数
function create(box, desk) {
var f = obj(box.prototype);
f.constructor = desk; //调整原型构造指针
desk.prototype = f;
}
function Box(name) {
this.name = name;
this.arr = ['apple','pear','orange'];
}
Box.prototype.run = function () {
return this.name;
};
function Desk(name, age) {
Box.call(this, name);
this.age = age;
}
//通过寄生组合继承实现继承
create(Box, Desk); //这句话用来替代Desk.prototype = new Box();
var desk = new Desk('Lee',100);
desk.arr.push('peach');
alert(desk.arr);
alert(desk.run());
临时中转函数和寄生函数主要做的工作流程:
临时中转函数:返回的是基类的实例对象函数
寄生函数:将返回的基类的实例对象函数的constructor指向派生类,派生类的prototype指向基类的实例对象函数(是一个函数原型),从而实现继承。
-------------------------------------------------------------------------------------------------------------------------------------
完
转载需注明转载字样,标注原作者和原博文地址。
更多阅读:
http://www.108js.com/article/article1/10201.html?id=1092
https://msdn.microsoft.com/zh-cn/library/bb397568.aspx
js面向对象理解的更多相关文章
- 带你一分钟理解闭包--js面向对象编程
上一篇<简单粗暴地理解js原型链--js面向对象编程>没想到能攒到这么多赞,实属意外.分享是个好事情,尤其是分享自己的学习感悟.所以网上关于原型链.闭包.作用域等文章多如牛毛,很多文章写得 ...
- 新手如何理解JS面向对象开发?
今天有时间讲讲我对面向对象的理解跟看法,尽量用通俗的语言来表达,多多指教! 如今前端开发已经越来越火了,对于前端开发的要求也是越来越高了,在面试中,经常有面试官会问:你对JS面向对象熟悉吗? 其实,也 ...
- 简单粗暴地理解js原型链–js面向对象编程
简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...
- js面向对象怎么理解
js面向对象怎么理解 <一>. 认识对象.首先要认识对象:在编程中,对象(object)是具体的某一个实例,唯一的某一个个体.如:电脑就是一个统称,而你面前的这一台电脑就是对象.而电脑的统 ...
- JS面向对象编程(进阶理解)
JS 面向对象编程 如何创建JS对象 JSON语法声明对象(直接量声明对象) var obj = {}; 使用 Object 创建对象 var obj = new Object(); JS对象可以后期 ...
- js面向对象学习 - 对象概念及创建对象
原文地址:js面向对象学习笔记 一.对象概念 对象是什么?对象是“无序属性的集合,其属性可以包括基本值,对象或者函数”.也就是一组名值对的无序集合. 对象的特性(不可直接访问),也就是属性包含两种,数 ...
- JS面向对象(2) -- this的使用,对象之间的赋值,for...in语句,delete使用,成员方法,json对象的使用,prototype的使用,原型继承与原型链
相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...
- JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式
相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...
- 浅谈JS面向对象之创建对象
hello,everybody,今天要探讨的问题是JS面向对象,其实面向对象呢呢,一般是在大型项目上会采用,不过了解它对我们理解JS语言有很大的意义. 首先什么是面向对象编程(oop),就是用对象的思 ...
随机推荐
- 对于单文本或者div的内容怎么在显示东西过多的情况下实现显示隐藏
js代码: $(function () { var o = document.getElementById("newsdetail_ArticleContent"); Subt(o ...
- mysql与mysqli的一些区别和方法
一.mysql与mysqli的概念相关: 1.mysql与mysqli都是php方面的函数集,与mysql数据库关联不大. 2.在php5版本之前,一般是用php的mysql函数去驱动mysql数据库 ...
- 导出为shape文件
private void barButtonItem2_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)//导出为s ...
- 转载:SQL按照日、周、月、年统计数据的方法
转载源:http://www.jb51.net/article/42613.htm SQL按照日.周.月.季度.年统计数据的方法 方式一: --按日 select sum(consume),day([ ...
- 1 springboot创建项目
文章采用idea工具进行springboot项目创建 1点击 New Project 选择[Spring Initializr] 选择Jdk版本其他默认即可 点击Next 2添加项目信息 文章即使用默 ...
- ionic开发中遇到的问题
开发调试过程中,会遇到这样的问题:同源策略请求url禁止请求. 一 网上搜的结果基本是2类: 1. 同源策略请求被阻止, 跨域问题,大家建议添加Access-Control-Allow-Origi ...
- Java设计模式—建造者模式
建造模式: 将一个复杂的对象的构建与它的表示分离,使得同样的构建 过程可以创建不同的. 建造模式表示是将复杂的内部创建封装在内部,对于外部调用的人来说,只需要传入建造者和建造工具,对于内 ...
- Visualizing CNN Layer in Keras
CNN 权重可视化 How convolutional neural networks see the world An exploration of convnet filters with Ker ...
- linux系统下安装ssl证书(tomcat)
1.申请ssl证书 2.下载ssl证书 打开此网址 https://myssl.com/cert_convert.html 将证书文件(xxx.com.crt)和密钥文件上传(xxx.com.key ...
- vmware centos 安装
一.分区 一块硬盘主分区+扩展分区最多只能有4个,其中扩展分区最多只能有1个.扩展分区不能写入数据,只能包含逻辑分区.这些都不是linux的限制,而是硬盘结构的限制. 分区号 第一种分区法: |--- ...