面向对象,创建对象,构造函数,原型,原型链

面向对象

对象是一系列无序属性的集合。

j权威指南:

对象是js的基本数据类型,它是一种复合值,它将很多值(原始类型或者其他值)聚合在一起,可通过名字访问这些值。

对象的内部属性有:

  • 数据属性
    可配置(表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性) ,可枚举(默认为true),可写(默认为true),值(包含这个属性的数据值,默认undefined)

  • 访问器属性
    可配置(表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性),可枚举(默认为true),[[get]]读取属性时调用的函数,[[set]]写入属性调用的函数,get,set默认都为undefined

面向对象:

我理解的就是指关注对象,以对象作为出发点来进行思考进行编程的一种方式。
另一种就是面向过程。
网上看到这个例子:一个木匠要做一个盒子,面向对象就是关注盒子要做成什么样,然后再去想需要什么材料。
面向过程就是不管做什么盒子,材料随取随用。

面向对象的三个特征

封装,继承,多态。
封装呢:我理解就是指把对象封装成抽象的一类,比如我们都是一个个人,但是我们可以统称人类。光说个人类好像也没有指向具体的某个实体,这就是说抽象….把对象的某些属性对可信的就让它们防问,不可信的就不能防问。
继承:就像是人类,这是一个对象,我们每个人都是人类,有相同的人类构造。
多态:就比方是虽然我们都是人类,但是每个人又都是不一样的。

创建对象

在js中创建对象有很多的方法:
字面量:

var person1 = {
    name: "one",
    job: "artist",
    hand:2,
    foot:2
}

但是这样,如果我要写一个和person1的属性一样的也有手和脚的对象person2,那又要重新像上面一样重新写一次
就很麻烦。
于是有了工厂模式

工厂模式

就是在函数里面新建个对象,然后通过传的参数,来返回这个对象:

function person(name,job){
    var person = new Object();
        person.name = name,
        person.job = job,
        person.hand = 2,
        person.foot = 2
    return person;
}
 var person1 = person("zhuyi","student");
    alert(person1.name);//zhuyi

但是这样一来虽然我建立person2并不需要再写一堆了,这个问题解决了,但是…怎么判断person1是什么类呢,它是人还是物呢?怎么通过person1来找到它的类别呢?

构造函数模式

构造函数和一般的函数其实….好像也没什么区别,也就是在调用它的时候前面加了个new,它内部也有点变化啦:

  • 一般函数名字的首字母都会大写
  • 它不会像上面的那个person函数一样显式创建一个对象
  • 直接将属性和方法赋给了对象
  • 一般没有return语句

再来说一下new操作符,比如上面var person = new Object(); 这里的new实际上是
1)先创建了一个空对象
2)把Object这个构造函数的作用域赋给上面创建的那个新空对象,然后this就指向了这个新空的对象
3)执行Object这个构造函数中的代码,为这个空对象添加了一系列属性
4)返回给person,这里的person就是一个基本类型–对象

把上面的那个person改成构造函数的方式:

 function person(name,job) {
//        var person = new Object(); 没有明显创建对象
        this.name = name, //this先指向了空对象,再指向赋值后的对象person1
                this.job = job,
                this.hand = 2,
                this.foot = 2
//        return person; 没有明显返回 因为这两步在new和赋值来完成了
    }
    var person1 = new person("zhuyi","student");
    alert(person1.name); //zhuyi
    alert(person1.job); //student

在此之前,this的其他的用法,这篇笔记记录了:
http://blog.csdn.net/u014106213/article/details/77966422
总之this在这里就是说这个方法属于谁。

通过这个方法呢,也达到了同样的创建person1的对象的效果,但是这样有一个不一样的,也是解决上面说到没办法去知道person1是那个抽象来的类别的问题:
person1现在是person的一个实例,现在这个对象person1通过构造函数来创建的话,它通过一个属性,叫构造函数属性,constructor,这个属性就是指向了它的类别,person,但是这个属性并不是它自己本身有的,是它继承而来(后面会提及):

alert(person1.constructor);

这样alert一下,会返回person那个函数,如果用来检查某个对象是什么类型,也可以用以下这个:

alert(person1 instanceof person); //true

instanceof,翻译成中文就是说,这个a是不是b的一个实例,是就返回true,不是就是false

原型模式

接下来,再看一下这个person函数,这里面像是名字,工作这些会不一样的,但是hand和foot一直都一样,那每次来新建个人就要重新把他们这些公共属性赋值给新人,就造成了资源的浪费。于是又有了原型模式:

我理解的原型就是一个存放公共属性的一个对象。它的英文名叫prototype,这个属性是函数才有的
它保存了一些公共的属性。同时,它有一个属性叫constructor,这个属性指向这个函数本身。

用原型模式来写上面的内容:

function person(name,job) {
        this.name = name,
        this.job = job,
        person.prototype.hand = 2,
        person.prototype.foot= 2
    }
    var person1 = new person("zhuyi","student");
    alert(person.hand);    // 共享prototype的2

这个时候,再新建一个对象person2的话,hand和foot这两个属性都是共享
他们都能访问到。
这时候的实例**person1其实它的内部包含了一个指针(内部属性),这个属性将指向构造函数的原型对象。
**es5叫这个为[[prototype]],又__proto__.它是每个对象都有的。
实际上上面提及的实例的constructor,也是继承自构造函数的prototype

这里写图片描述

那么现在似乎可以发现:分为两种,一种是函数,而每个函数都可以作为构造函数的,一种是普通实例对象:
1)prototype是函数才有的,中文叫原型,也就是说实例的共同特征的“源头”
2)constructor是一个存在构造函数的prototype中的对象,也就是说实例(被构造函数new出来的对象)自身其实没有这个对象,而原型(构造函数)都存在这样一个属性,构造函数的constructor会指向自己,这个属性名字中文是构造器,也就是指向构造函数的一个属性
3)而__proto__ 是对象都有的属性,也就是说不管是构造函数还是实例,都有着这样一个属性,它指向构造函数的prototype,构造函数这个属性存放在prototype中

上面说person1的constructor指向person,其实是person这个函数的prototype中有constructor这样一个对象,这个对象指向了person,而person1的__proto__ 指向了person的prototype,访问person1的时候,顺着这个指针,就到了person的prototype中的constructor,这就找到了person。

那如果这时候我在某个实例上也同样给它自己建立一个属性叫做hand,而且给它设置为3呢?
如果我alert(person1.hand),这时候它会弹出几呢?

function person(name,job) {
        this.name = name,
        this.job = job,
        this.hand = 3,
        person.prototype.hand = 2,
        person.prototype.foot= 2
    }
    var person1 = new person("zhuyi","student");
    alert(person1.hand);//3

每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性,搜索首先从对象实例
本身开始,如果在实例中找到了具有给定名字的属性,则返回该属性的值,如果没有找到,则继续搜索指针指向的
原型对象。当为对象实例中添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性,使用delete删除掉
这个实例属性后,我们还是能重新访问原型中的这个属性。

因此上面的那段代码中,首先搜索person1中的实例属性hand,搜索到了,就会返回,不会再搜索原型中的
hand了,而如果删除掉这个person1中的hand,原型对象的hand还是能再次访问到

原型链

首先,js中有undefined,null,object,string,number,boolean,这几种基本类型。而object又有Date,function,array,regExp等作为它的实例的类型。
看上面的图会发现,新创建出来的对象person1是通过属性中有一个[[prototype]]属性,也就是__proto__.来继承person这个函数中的共享对象的。
person1是属于基本类型object,而person的类型虽然也是对象,但是更细分下去,它属于function。
那么person也同样有__proto_ 这个属性,它又指向的是哪里呢?

当我们声明一个函数的时候,函数的__proto__ 指向的是一个构造函数function的prototype,每个函数都是function的实例。

这个function就相当于是整个函数的“祖先”,每个函数通过直接声明出来的都会通过__proto__ 来指向它。
而function也同样是object的实例,function也是对象,它的__proto__ 也指向的是构造函数object()的prototype,而Object的__proto__ 又是指向了null。(null这个是相当于规定,null在js中,逻辑上是一个空对象指针,记住它是原型链顶端就可以,从无到有)
这样就构成了一条完整的原型链。
在上面的基础上:

var apple = new Object();

创建一个apple普通对象,以下是图:

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值