js面向对象--笔记(二)

        先上张图(应该没画错吧)

        以下内容参考于JavaScript高级设计程序(第三版)

        创建函数的方式   1.函数表达式  var peo = function(){ name : "嗯嗯" };

                                    2.函数声明 function Peo(name) { this.name = name; };

                                    3.var p = new Function("a", "b", "return a + b"); (不推荐)

        创建对象(new)过程:

                1.在内存申请地址,存储对象

                2.设置this为当前对象

                3.设置属性和方法

                4.返回this

       // 参考高级设计139页

       属性的默认特征:1.Configurable,能否delete的属性,默认为true

                                    2.Enumerable,能否for-in的属性,默认true

                                    3.Writeable,能否修改属性值,默认true

                                    4.Value,该属性的数据值,默认undefined

        一开始,一个一个地new对象,很麻烦,所以出现了工厂模式

        工厂模式:

                function my(name, age) {

                        var o = new Object();

                        o.name = name;

                        o.age = age;

                        o.sayHi = function() { alert("hi"); }

                        return o;

                }

        虽然工厂模式能够批量生产对象,但是用instanceOf得到的总是Objcet,但是我想要的是People、Animal这种特殊的对象

        构造函数:

                function People(name, age) {

                        this.name = name;

                        this.age = age;

                        this.sayHi = function() {

                                alert(this.name);

                        }

                }

        但是构造函数也有缺点,就是创建出来的实例对象,如果调用sayHi这个方法,其实都不是同一个方法(虽然它们没区别),因为没创建实例对象都会在堆中开出一块内存,每个对象都有各自的sayHi方法。所以原型来了

        原型

                作用:共享数据、节省内存,继承

                缺点:它的优点也是它的缺点,因为共享的是同一个数据,如果这个数据是引用类型的属性,实例对象1修改了引用属性,当实例对象2拿出这个引用属性是修改之后的

                原型简写: People.prototype = {

                                                constructor : People; (记得要写)

                                                name : "哈哈";

                                   }

                注意:如果先实例对象再添加原型,你会访问不到原型里的东西,这个不难理解,因为实例时的原型没有这个属性或方法,所以报错,这里可能会疑惑,后面不是添加了原型吗?这里要借助最上面的图,创建实例对象后跟图上是一模一样的,但是当添加原型后,此时构造函数的原型对象已经是另外一个了,构造函数和实例对象原本是指向同一个但是现在各自指向各自的。(所以说为什么要先实例对象再添加原型)。

       继承

       1.利用原型继承

              

      当Person原型改变了指向(指向Animal的实例对象),而Animal的实例对象又指向了Animal的原型,所以此时可以用Animal中的任何属性和方法,而原来的getName方法就访问不了,所以会报错(peo.getName())。当然如果把Peoson.prototype.getName...这行代码放到改变原型指向的代码之后(new Animal这行代码之后),就不会报错了,实际上就是给Animal原型添加一个方法,所以可以访问。注意:如果此时添加的是对象字面量(就是Peoson.prototype =  { ...}),这样会覆盖new Animal这行代码。

       可是这样也会有问题,如果我在后面再添加var peo1 = new Peoson("ab");     peo1.age的值也是19,无论再创建多少个实例对象,值都是一样。(也就是说改变原型的指向时把Animal中的属性都赋值了,所以继承下来的值都是相同的)。

       2.借用构造函数

       call(obj, "a", "b"...)

       apply(obj, ["a", "b"])

       这两个方法除了参数传入不同之外,没有任何区别

       function test() {

              result.call(this, "a");   // this(也就是test的实例对象)继承result,简单粗暴一点就是将result里的this全部换成test的实例对象

       }

      缺点跟构造函数的缺点一样,方法都不是同一个地址的

      3.上面两种方法组合使用

            用原型来继承方法,用借用构造函数来继承属性

      4.原型式继承(Object.create())

            var p = Object.create(People, { name : {value :"a"}; })

       5.寄生式继承(createAnother())

              var p = createAnother(People);   p.sayHi = function() { alert("hi") };

       6.寄生组合继承

              function inheritPrototype(subType, superType) {

                     var prototype = object(superType.prototype);  // 创建对象

                     prototypr.constructor = subType;  // 添加构造器

                     subType.prototype = prototype;  // 改变原型

              }

猜你喜欢

转载自blog.csdn.net/Yi_xuan_sky/article/details/81538416
今日推荐