05_JS面向对象

继承的实现方式

在前面,我们的结论就是可以通过继承来让一个对象可以使用另一个对象的属性和方法,那怎么实现继承呢?

  • 最简单的继承实现
    混入式继承
<script type="text/javascript">
    var obj = {
        name:"布莱德皮特",
        age:12,
        sayHello: function () {
            console.log("Hello World");

        }
    }
    var o = {};

    //混入式继承
    for(var k in obj){
        o[k] = obj[k];
    }

    console.log(o);
</script>
  • 原型继承
<script type="text/javascript">
    //原型继承
    //利用原型中的成员可以被其他相关的对象共享这一特性,可以实现继承
    //这种实现继承的方式,就叫做原型继承

    //  1,给原型对象中添加成员(通过对象的动态特性) 不是严格意义上的继承
    function Person(name, age){
        this.name = name;
        this.age = age;
    }
    Person.prototype.sayHello = function () {
        console.log("Hi,nihao");
    }
    var p = new Person("迪丽热巴",24);
    p.sayHello();
    //此方式属于对象继承了原型对象
</script>
  • 直接替换原型对象的方式继承
<script type="text/javascript">
    //  2,直接替换原型对象
    function Son(name, age){
        this.name = name;
        this.age = age;
    }
    var parent = {
        sayHello: function () {
            console.log("Hi,Wife");
        }
    }
    Son.prototype = parent;
    var s = new Son("蜡笔小新",12);//一定要在设置原型后面
    console.log(Son.prototype);
    s.sayHello();
    //s对象继承了原型对象(parent对象)
</script>

注意:使用体会原型的方式实现继承的时候,原有的原型中的成员会消失

  • 利用混入的方式给原型对象添加成员
<script type="text/javascript">
    //  3,利用混入的方式给原型对象添加成员
    function Son(name, age){
        this.name = name;
        this.age = age;
    }
    var s = new Son("蜡笔小新",12);//可以在设置原型之前
    var parent = {
        sayWife: function () {
            console.log("Hi,My Wife!");
        }
    }
    for(var k in parent){
        Son.prototype[k] = parent[k];
    }
    s.sayWife();
</script>
  • 经典继承方式的实现
<script type="text/javascript">
    //《JavaScript语言精粹》作者提出了一个方式来实现继承
    function inherit(obj){
        var o = {};
        o.__proto__ = obj;
        return o;
    }
    var o = inherit({name:"张三"});
    console.log(o);

    //经典继承的语法
    //Object.create(obj)
    //返回值为一个对象,继承自参数中的obj
    //这个方法是ES5中出来的,所以存在兼容性问题
//    var o = {
//        name:"李四"
//    }
//    var obj = Object.create(o);
//    console.log(obj);

    //如何处理Object.create的兼容性问题
    var o = {
        name:"李四"
    }
    //检测浏览器的能力,如果没有Object.create方法就给他添加一个(不推荐使用)
    if(Object.create){
        var obj= Object.create(o)
    }else{
        Object.create = function (o) {
            function F(){}
            F.prototype = o;
            var obj = new F;
            return obj;
        }
        var obj = Object.create()
    }

    var o1 = Object.create(o);
    console.log(o1);

    //自己定义个函数
    function create(obj){
        if(Object.create){
            return Object.create(obj)
        }else{
            Object.create = function (obj) {
                function F(){}
                F.prototype = obj;
                return new F;;
            }
        }
    }
    var o = {
        age:12,
    }
    var obj = create(o);
    console.log(obj);
</script>

原型继承

每一个构造函数都有prototype原型属性,通过构造函数创建出来的对象都继承自该原型属性。所以可以通过更改构造函数的原型属性来实现继承。

function Dog(){
    this.type = "yellow Dog";
}

function extend(obj1, obj2){
    for (var k in obj2){
        obj1[k] = obj2[k];    
    }
};

//使用混入的方式,将属性和方法添加到构造函数的原型属性上,构造函数所创建出来的实例就都有了这些属性和方法。
extend(Dog.prototype, {
    name:"",
    age:"",
    sex:"",
    bark:function(){}

})

//使用面向对象的思想把extend方法重新封装
//extend是扩展的意思,谁要扩展就主动调用extend这个方法
//所以extend应该是对象的方法,那现在我们要扩展的是构造函数的原型对象
//所以给构造函数的原型对象添加一个extend方法

//如下:

Dog.prototype.extend = function(obj){
    for (var k in obj){
        this[k]=obj[k];
    }
}

//调用方式就变成了下面这种形式

Dog.prototype.extend({
    name:"",
    age:"",
    sex:"",
    bark:function(){}
});

继承的应用


<script type="text/javascript">
    var arr = [1,2,5,3,8,1];
    //给数组添加一个sayHello方法
    Array.prototype.sayHello = function () {
        console.log("您好,我告诉你数组的长度是:"+this.length);
    }
    arr.sayHello();
    //但是这样属于扩展内置对象,就是给内置对象新增成员

    //在多人开发时,大家都扩展内置对象,如果名称一样会有问题
    //内置对象中原来有的成员,可能会被替换,那内置对象的功能会丧失
    //在ECMScript升级时,扩展内置对象的新增成员可能有被覆盖的危险
    //所以在项目中应避免扩展内置对象

    //避免扩展内置对象,使用继承的方式
    function MArray(){

    }
    var arr = new Array();
    MArray.prototype = arr;
    //mArr这个对象就继承自arr
    var mArr = new MArray();
    mArr.push(1);
    mArr.push(2,3,4,5);
    console.log(mArr);//打印:(5) [1, 2, 3, 4, 5]
</script>

属性搜索原则

访问一个对象的成员的时候,首先是在实例中找,没有找到, 就去原型中找, 但是原型中没有怎么办?

属性搜索原则

所谓的属性搜索原则,也就是属性的查找顺序,在访问对象的成员的时候,会遵循如下的原则:

  • 首先在当前对象中查找,如果找到,停止查找,直接使用,如果没有找到,继续下一步
  • 在该对象的原型中查找,如果找到,停止查找,直接使用,如果没有找到,继续下一步
  • 在该对象的原型的原型中查找,如果找到,停止查找,直接使用,如果没有找到,继续下一步。
  • 继续往上查找,直到查找到Object.prototype还没有, 那么是属性就返回 undefied,是方法,就报错xxx is not a function

原型链

每一个对象都有原型属性,那么对象的原型属性也会有原型属性,所以这样就形成了一个链式结构,我们称之为原型链。

原型链结构

凡是对象就有原型, 原型又是对象, 因此凡是给定义一个对象, 那么就可以找到他的原型, 原型还有原型. 那么如此下去, 就构成一个对象的序列. 称该结构为原型链.
  使用构造函数创建出对象, 并且没有利用赋值的方式修改原型, 就说该对象保留默认的原型链.
  默认原型链结构是什么样子呢?

function Person() {
}

var p = new Person();
// p 具有默认的原型链

默认的原型链结构就是:当前对象 -> 构造函数.prototype -> Object.prototype -> null
在实现继承的时候, 有时会利用替换原型链结构的方式实现原型继承, 那么原型链结构就会发生改变

<script type="text/javascript">
    //1,什么是原型链
    //  每个构造函数都有原型对象
    //  每个对象都有构造函数
    //  每个构造函数的原型对象都是一个对象
    //  那么这个原型对象也会有构造函数
    //  那么这个原型对象的构造函数也会有原型对象
    //  这样就会形成一个链式的结构,称为原型链
    function Person(){

    }
    var p = new Person();
    //p的原型是一个Object对象
    console.log(p.__proto__);
//    p---->Person.prototype ----> Object.prototype ----> null
    //属性的搜索规则
    //  1.当访问一个对象的成员的时候,会现在自身找有没有,如果找到直接使用,
    //  2.如果没有找到,则去当前对象的原型对象中去查找,如果找到了直接使用,
    //  3.如果没有找到,继续找原型对象的原型对象,如果找到了,直接使用
    //  4.如果没有找到,则继续向上查找,直到Object.prototype,如果还是没有,就报错

    //原型继承
    //通过修改原型链结构实现的继承,就叫做原型继承
</script>

复杂的原型链

<script type="text/javascript">
    function Animal(){
        this.age = 8;
    }
    Human.prototype = new Animal;
    Human.prototype.constructor = Human;
    function Human(){
        this.name = "杨迪";
    }
    Teacher.prototype = new Human;
    Teacher.prototype.constructor = Teacher;
    function Teacher(){
        this.work = "教书";
    }
    BadTeacher.prototype = new Teacher;
    BadTeacher.prototype.constructor = BadTeacher;
    function BadTeacher(){
        this.teaching = "打人";
    }

    var bt = new BadTeacher;
//    console.log(bt);
    //Teacher {work: "教书", constructor: function}
    console.log(bt.__proto__);
    //Human {name: "杨迪", constructor: function}
    console.log(bt.__proto__.__proto__);
    //Animal {age: 8, constructor: function}
    console.log(bt.__proto__.__proto__.__proto__);
    //Object {constructor: function}
    console.log(bt.__proto__.__proto__.__proto__.__proto__);
    //Object {__defineGetter__: function, __defineSetter__: function, hasOwnProperty: function, __lookupGetter__: function, __lookupSetter__: function…}
    console.log(bt.__proto__.__proto__.__proto__.__proto__.__proto__);
    //null
    console.log(bt.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__);

    var arr = [];
    console.log(arr);
    //[constructor: function, toString: function, toLocaleString: function, join: function, pop: function…]
    console.log(arr.__proto__);
</script>

Object.prototype的成员

  • constructor
  • hasOwnProperty
  • propertyIsEnumerable
  • Object.defineProperty();
  • toString 和 toLocaleString
  • valueOf
  • __proto__
<script type="text/javascript">
    //1.constructor
    //原型对象内的一个属性,指向该原型对象相关联的构造函数

    //2.hasOwnProperty
    //一个方法,用来判断对象本身(不包含原型)是否拥有某个属性
    function People(){
        this.name = "王久";
    }
    People.prototype.name = "张三";

    var pp = new People();
    console.log(pp.name);
    console.log(pp.hasOwnProperty("name"));//true
    console.log(pp.hasOwnProperty("__proto__"));//false

    //3.propertyIsEnumerable
    //    1. 判断属性是否属于对象本身
    //    2. 判断属性是否可以被遍历
    console.log(pp.propertyIsEnumerable("name"));//true

    //  Object.defineProperty();
    // 使用以上方法添加属性的时候,可以附加一些信息,
    // 例如这个属性是否可写 可读  可遍历

    //4.toString 和  toLocaleString
    var o = {};
    console.log(o.toString());//[object Object]
    console.log(o.toLocaleString());//[object Object]

    var now = new Date();
    console.log(now.toString());//Wed Jul 19 2017 23:57:53 GMT+0800 (China Standard Time)
    console.log(now.toLocaleString());//2017/7/19 下午11:57:53


    function Person(){}
    var p = new Person();
    console.log(1+p);//1[object Object]
    //5.valueOf
    function Person1(){
        this.valueOf = function () {
            return 123;
        }
    }
    var p1 = new Person1();
    console.log(1 + p1);//124

    //在对象参与运算的时候
    //  1.默认的会先去调用对象的valueOf方法,
    //  2.如果valueOf获取到的值,无法进行运算 ,就去去调用p的toString方法  最终做的就是字符串拼接的工作

    //6. __proto__
    //原型对象对象中的属性
    //可以使用 对象.__proto__ 去访问原型对象
</script>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • 博客内容:什么是面向对象为什么要面向对象面向对象编程的特性和原则理解对象属性创建对象继承 什么是面向对象 面向对象...
    _Dot912阅读 1,424评论 3 12
  • 本章内容 理解对象属性 理解并创建对象 理解继承 面向对象语言有一个标志,那就是它们都有类的概念,而通过类可以创建...
    闷油瓶小张阅读 851评论 0 1
  • 官方中文版原文链接 感谢社区中各位的大力支持,译者再次奉上一点点福利:阿里云产品券,享受所有官网优惠,并抽取幸运大...
    HetfieldJoe阅读 2,998评论 4 14
  • 今天一早,断舍离充斥在我的朋友圈,就因为昨晚加入了一个微信群,这个群是为了听收纳课而建立的,大家为了收纳走在一起了...
    兰花子阅读 157评论 0 0
  • 野猪和马一起吃草,野猪时常使坏,不是践踏青草,就是把水搅浑。马十分恼怒,一心想要报复,便去请猎人帮忙。猎人说除非马...
    中炯阅读 1,222评论 0 1