# oo

##创建对象

1. 原型、构造函数、实例之间的关系

* 原型的construct->构造函数;调用isPrototypeOf(obj)方法可以判定和实例的关系;
 * 构造函数的prototype->原型;
 * 实例的__proto__ ->原型(仅在chrome,safari,Firefox中存在,而共有的是[[prototype]]);用getPrototypeOf()方法可以返回[[prototype]]的值;
 * 构造函数后构造函数的‘子类’new产生一个实例,可以用instanceOf 操作符来检测构造函数是否出现在原型链上。

2. 说明:

* 一个函数在声明之后就会有prototype对象,对象的constructor属性所存放的指针指向该函数。
 * 对原型进行赋值,就让这个prototype中的指针指向了一个新的对象,里面的constructor属性自然会丢失。如果把父类的值赋给了它,那么这个constructor就是父类实例的值。父类实例并没有这个属性,于是继承父类的原型中的constructor。所以,子类构造函数的(this.constructor)的值通过这样的步骤获得:
 
    子类实例(没有)--子类原型 (没有)--父类原型(有,为父类构造函数)

3. new关键字的理解

new的作用就是新建一个作用域,将this指向该作用域,然后执行函数中的代码。不用new关键字,那么this将指向globle对象,在浏览器中是window对象。

4. 检测对象和属性的关系
 
(1)

* in操作符 能够访问该属性
 * hasOwnProperty() 存在实例中
 * !obj.hasOwnProperty() && in 存在原型中

(2)

* for-in循环 枚举出 包含实例中的属性和原型中 可枚举的属性;
 * Object.keys(obj) 返回一个数组 可枚举的实例属性;
 * object.getOwnPropertyNames(obj) 得到所有实例属性,无论是否可以枚举;

##实现继承

1. 原型链继承

2. 借用构造函数(又叫伪造对象,对象冒充法,经典继承等)

3. 组合继承(又叫伪经典继承)

function Anm(name,age) {
            this.name = name;
            this.age = age;
        }
        Anm.prototype.sayBye = function () {
            console.log(this.name + ' say bye to you!');
        };
        function Dog(food, name, age) {
            //从父类中,通过call或apply方法继承属性
            Anm.call(this, name, age);
            this.food = food;
        }
        //子类通过设置原型等于父类的一个实例的方式,继承方法
        Dog.prototype = new Anm();
        Dog.prototype.constructor = Dog;
        Dog.prototype.sayHello = function() {
            console.log(this.name + ' say hello to me!')
        };
        dog1 = new Dog('shit', '小黄狗', 15);
        console.log(dog1);    //{name: "小黄狗", age: 15, food: "shit", constructor: function, sayHello: function…}
        dog1.sayBye();    //小黄狗 say bye to you!
        dog1.sayHello();    //小黄狗 say hello to me!

这种继承,能够让子类产生的实例拥有自己的属性,又可以从父类的原型上面继承得到公用的方法。所以成为javascript中最常用的继承模式。

4. 原型式继承

function Anm(klass) {
            this.klass = klass;
        }
        var dog1 = Object.create(gou, {
            name: {
                configurable: true,
                enumerable: true,
                writable: true,
                value: '小黄'
            },
            birthyear: {
                value: 2012
            },
            age: {
                get: function () {
                    var thisTime = new Date();
                    return thisTime.getFullYear() - this.birthyear;
                }
            }
        });
        console.log('修改前的对象');
        console.log(dog1);  //Object {name: "小黄", birthyear: 2012, age: 3, klass: "狗狗"}
        dog1.name = '小李';
        dog1.birthyear = 2010;
        console.log('修改后的对象');  //Object {name: "xiaoli", birthyear: 2012, age: 3, klass: "狗狗"}
        console.log(dog1);

Object.create()方法接受两个参数,第一个是作为原型的对象,第二个是为新队想定义额外属性的对象,以JSON格式,每一个要新增的属性都是该对象中一个属性,它的值也是一个描述符对象。

属性有数据属性(如上面的name和birthyear)和访问器属性(如上面的age),如果只写入一个特性,其余特性的值将会被设置为false。所以上面的birthyear是无法改动的。
    
    这种方式可以在指向让一个对象与另一个对象保持类似的情况下使用,不用去进行构造函数的创建。

5. 寄生式继承

上面的Object.create()方法额可以只创第一个参数,然后在对返回的函数添加属性,再把这整个过程封装起来,这种方式叫作寄生式继承。
    
6. 寄生组合式继承

子类的原型在Dog.prototype = new Anm()过程中,为它添加了Anm中属性klass(值为undifiend),同时Dog构造函数中,同样为实例添加了klass,相当于在原型和实例中都创造了属性。如果属性很多的话,这是一种浪费。如果能够不让子类的原型产生这些属性,直接让他的[[prototype]]指向父类的原型的话,那么就能够继承父类的方法了。
    我们先封装一个方法:

function inheriyPrototype(subType, superType) {
            var newPrototype = Object.create(superType.prototype);
            subType.prototype = newPrototype;
            newPrototype.constructor = subType; //重写了subType.prototype后丢失了自己的constructor,这里进行补写
        }

这个方法让子类不通过父类的实例赋值,而是让它的[[prototype]]直接指向父类的实例。
    
    实际上,这个子类的原型是一个空函数创建的,这个空函数的原型等于父类的原型。所以就让这个空函数的实例只有一个[[prototype]],再把这个实例赋值给了子类的原型,加上constructor属性。就实现了不创造多余属性的目的。

接下来:

function Anm(klass) {
            this.klass = klass;
        }
        Anm.prototype.sayKlass = function () {
            console.log(this.klass);
        };
        function Dog(name, klass) {
            Anm.call(this, klass);
            this.name = name;
        }
        inheriyPrototype(Dog, Anm);
        var dog1 = new Dog('小黄', '犬科动物');
        console.log(dog1);  //Dog {klass: "犬科动物", name: "小黄", constructor: function, sayKlass: function}
        dog1.sayKlass();    //犬科动物
        console.log(Dog.prototype);     //Dog {constructor: function, sayKlass: function}
        console.log(Dog.prototype.isPrototypeOf(dog1));        //true
        console.log(Anm.prototype.isPrototypeOf(dog1));        //true

现在很多程序员普遍认为寄生组合式是最理想的继承范式。在YUI中的一些方法上已经开始在使用了。

javascript中创建对象和实现继承的更多相关文章

  1. 【转】JavaScript中的原型和继承

    请在此暂时忘记之前学到的面向对象的一切知识.这里只需要考虑赛车的情况.是的,就是赛车. 最近我正在观看 24 Hours of Le Mans ,这是法国流行的一项赛事.最快的车被称为 Le Mans ...

  2. 深入理解JavaScript中创建对象模式的演变(原型)

    深入理解JavaScript中创建对象模式的演变(原型) 创建对象的模式多种多样,但是各种模式又有怎样的利弊呢?有没有一种最为完美的模式呢?下面我将就以下几个方面来分析创建对象的几种模式: Objec ...

  3. 谈谈javascript中的prototype与继承

    谈谈javascript中的prototype与继承 今天想谈谈javascript中的prototype. 通常来说,javascript中的对象就是一个指向prototype的指针和一个自身的属性 ...

  4. javascript中创建对象的方式总结

    javascript中创建对象的方式总结 具体代码如下: //创建对象的方式: //创建方式一 var person=new Object(); person.name='jack'; person. ...

  5. javascript中创建对象的几种不同方法

    javascript中创建对象的几种不同方法 方法一:最直白的方式:字面量模式创建 <script> var person={ name:"小明", age:20, s ...

  6. JavaScript中创建对象的三种方式!

    JavaScript中创建对象的三种方式! 第一种 利用对象字面量! // 创建对象的三种方式! // 1 对象字面量. var obj = { // 对象的属性和方法! name: 'lvhang' ...

  7. javascript中的对象之间继承关系

    相信每个学习过其他语言的同学再去学习JavaScript时就会感觉到诸多的不适应,这真是一个颠覆我们以前的编程思想的一门语言,先不要说它的各种数据类型以及表达式的不同了,最让我们头疼,恐怕就是面向对象 ...

  8. Javascript中的prototype与继承

    通常来说,javascript中的对象就是一个指向prototype的指针和一个自身的属性列表.javascript创建对象时采用了写时复制的理念. 只有构造器才具有prototype属性,原型链继承 ...

  9. 深入 JavaScript 中的对象以及继承原理

    ES6引入了一个很甜的语法糖就是 class, class 可以帮助开发者回归到 Java 时代的面向对象编程而不是 ES5 中被诟病的面向原型编程. 我也在工作的业务代码中大量的使用 class, ...

随机推荐

  1. 2018 noip 备战日志

    我是写给自己看的…… Day1 10.8 今天开始停晚修课了,开始认真备战考试了. 今天晚上效率不错,竟然不会累,应该是平时一直这个时间写作业大脑高度集中, 现在换了编程也一样可以集中到这个状态 一些 ...

  2. 1.VMware虚拟机的安装

    1.找到安装软件 2.使用如下操作安装 3.选择接受协议 4.修改安装目录 5.如果上一步有修改,此步骤不用改路径 7.安装后创建桌面快捷方式 8.安装成功可以看到桌面上有快捷方式图标 安装结束 声明 ...

  3. EurekaLog是什么鬼?

    D的all工程文件打开后,莫名其妙就处于等待打开状态.因为最后一次调整是安装了RO9.0.所以一直怀疑是RO的原因.再加上win7授权问题,安装RO一直不顺当.所以折腾的时间最多. 其他把RO全部卸载 ...

  4. Drop a database in MongoDB

    http://www.linuxask.com/questions/drop-a-database-in-mongodb Drop a database in MongoDB Answer: Assu ...

  5. rmq问题和lca可以相互转化

    Sparse Table算法 一般RMQ的Sparse Table(ST)算法是基于倍增思想设计的O(Nlog2N) – O(1)在线算法 算法记录从每个元素开始的连续的长度为2k的区间中元素的最小值 ...

  6. POJ 1679

    求一次最小成树,求一次小生成树,若相等,则不唯一.否则,唯一. #include <iostream> #include <cstdio> #include <cstri ...

  7. JeeCG团队招聘啦!

    JeeCG团队招聘啦! 小团队攻坚,创业氛围浓厚.盼望有激情的你增加. 岗位描写叙述: 1,负责Jeecg.jeewx 微信管理系统相关的研发工作.2,高度參与整个产品设计.參与微信相关项目开发.3. ...

  8. 基于Dynamic Proxy技术的方法AOP拦截器开发

    在面向对象编程中,会用到大量的类,并且会多次调用类中的方法.有时可能需要对这些方法的调用进行一些控制.如在权限管理中,一些用户没有执行某些方法的权限.又如在日志系统中,在某个方法执行完后,将其执行的结 ...

  9. POJ 1166 The Clocks (暴搜)

    发现对这样的模拟题根本没啥思路了,本来准备用bfs的.可是结果超时了,这是參考别的人代码写的: #include <stdio.h> #include <iostream> # ...

  10. 学习Mockito - Mockito对Annotation的支持

    学习Mockito - Mockito对Annotation的支持 博客分类: test junit工作  Mockito支持对变量进行注解,例如将mock对象设为测试类的属性,然后通过注解的方式@M ...