javascript基础(3)

来源:互联网 发布:百度域名跳转代码 编辑:程序博客网 时间:2024/06/07 15:29

面向对象

一、创建对象

a. 工厂模式

    function createPerson(name,age,job){        var o = new Object();        o.name = name;        o.age = age;        o.job = job;        o.sayName = function(){            alert(this.name);        }        return o;    }    var p1 = createPerson("terry",11,"boss");    var p2 = createPerson("larry",12,"daBoss");

工厂模式的问题

var t1 = typeOf p1; //object 无法对象识别,既所有对象都是Object类型

b. 构造函数模式
js中可以自定义构造函数,从而自定义对象类型的属性和方法
构造函数本身也是函数,只不过可以用来创建对象

function Person(name,age,job){    this.name = name;    this.age = age;    this.job = job;    this.sayName = function(){        alert(this.name);    }}var p1 = new Person("terry",11,"boss");var p2 = new Person("larry",12,"daBoss");

使用new操作符调用构造函数创建对象实际上经历了如下几个步骤

      1) 创建一个新对象      2) 将构造函数的作用域赋给新对象(this指向这个新对象)      3) 执行构造函数中的代码      4) 返回新对象。

这种创建对象的方法可以将实例标识为一种特定类型(例如Person类型)。

1.构造函数当做函数
Person(“larry”,12,”daBoss”)
当在全局作用域中调用一个函数时,this总是指向Global对象(window对象)。

2.构造函数的问题
每个方法都需要在每个实例上重新创建一遍,但是毫无必要。
可以在全局范围中声明一个函数,然后将引用传递给对象中的函数属性。但是这样
做会导致全局函数过多,体现不了对象的封装性
console.log(p1.sayName == p2.sayName); //false

c. 原型模式
每个函数都有一个属性:prototype(原型属性),这个属性是一个指针,指向一个对象,该
对象的用途是包含可以由特定类型的所有实例共享的属性和方法。

    function Person(){    }    Person.prototype.name = "tom";    Person.prototype.age = 22;    Person.prototype.job="boss";    Person.prototype.sayName = function(){        alert(this.name);    }    var p1 = new Person();    p1.name = "terry";    var p2 = new Person();    p2.name = "larry";  

创建了自定义的构造函数之后,其原型对象默认会取得constructor属性;当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。(指向的是原型对象而不是构造函数)

1.属性的访问
每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。
1) 首先从对象实例本身开始查找
2) 如果不在对象实例中,则继续搜索指针指向的原型对象。

2.删除实例属性
当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性。通过delete
操作符可以完全删除实例属性。

3.检测属性是否存在于实例中

      hasOwnProperty(p); 判断p指定的属性是否存在于实例中,如果存在返回true      console.log(p1.hasOwnProperty("name"));   //false 存在于原型中而不是实例对象中

4.原型与in操作符
1) 在for-in 可以访问存在于实例中的属性,以及原型中的属性
2) 单独使用

     a in b;  通过b对象可以访问到a属性的时候返回true,无论该对象在实例中还是在原型中     console.log("name" in p1);     //true     //判断一个属性是否在原型     function hasPrototypeProperty(obj,name){                //不在实例中但是可以访问到的属性属于原型属性         return !obj.hasOwnProperty(name) && (name in obj);     }

5.原生对象的原型
通过原生对象的原型,不仅可以取得所有默认方法的调用,而且可以定义新方法。可以向修改自定义对象的原型一样修改原生对象的原型,可以随时添加方法。

     String.prototype.startsWith = function(text){            return this.indexOf(text) == 0;     }     var msg = "Hello world";     alert(msg.startsWith("Hello"));    //true

6.原型对象的问题
所有实例在默认情况下都将取得相同的属性值,这种共享对于函数来说非常合适,但是包含引用数据类型的值就不太好

        Person.prototype = {            name : "briup",            friends : ["larry","terry"]        }        var p1 = new Person();        var p2 = new Person();        p1.name = "terry";        p1.friends.push("tom");        p1.friends; //["larry","terry","tom"]        p2.friends; //["larry","terry","tom"]

7.更简单的原型语法
将原型对象设置为等于一个对象字面量形式创建的新对象。实例对象使用效果相同,但是原型中的constructor属性不再指向Person,因为每创建一个对象,就会同时创建它的prototype对象,这个对象也自动获得constructor属性。这里我们重写了prototype对象,因此该原型中constructor属性就变成了新对象的constructor属性(Object)

      p1.constructor.prototype.constructor //Object      function Person(){      }      Person.prototype = {      //constructor: Person,   如果constructor比较重要,可以指定它的值,Enumerable ,true,默认为false         name:"tom",         age :22,         job :"boss",         sayName:function(){            alert(this.name);         }      }      //定义constructor属性,不可遍历      Object.defineProperty(Person.prototype,"constructor",{         enumerable : false,         value : Person      });

d.组合使用构造函数模式和原型模式
构造函数用于定义实例属性,原型模式用于定义方法和共享属性。
这种模式是目前在ECMAScript中使用最广泛,认同度最高的一种创建自定义类型的方法。

    function Person(name,age){        this.name = name,        this.age = age,        this.friends = []    }    Person.prototype = {        constructor : Person,        sayName:function(){            alert(this.name);        }    }    var p1 = new Person("terry",11);    var p2 = new Person("larry",12);    p1.friends.push("tom");    p2.friends.push("jacky");    console.log(p1);    console.log(p2);

二、继承
a. 原型链
每个构造函数都有一个原型对象,原型对象中都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。当原型对象等于另外一个类型的实例即继承
调用某个方法或者属性的步骤
1).搜索实例
2).搜索原型
3).搜索父类原型

        //定义父类类型        function Animal(){            this.name = "animal"            }        Animal.prototype = {            sayName : function(){                alert(this.name);            }        }        //定义子类类型        function Dog(){            this.color = "灰色"        }        //通过将子对象的原型对象指向父对象的一个实例来完成继承        Dog.prototype = new Animal();        //子对象的方法其实是定义在了类对象的实例上。        Dog.prototype.sayColor = function(){                alert(this.color);        }        var dog = new Dog();        console.log(dog);        dog.sayColor();        dog.sayName();

1.默认原型
所有函数默认原型都是Object的实例,默认原型中都会包含一个内部指针,指向
Object.prototype.

2.确定原型和实例的关系
1) 通过使用instanceof

      instance instanceof Object    //true      instance instanceof SuperType //true      instance instanceof SubType   //true

2) 通过使用isPrototypeOf()
只要是原型链中出现过的原型,都可以说是该原型链所派生的实例的原型

     Object.prototype.isPrototypeOf(instance)       //true     SuperType.prototype.isPrototypeOf(instance)    //true     SubType.prototype.isPrototypeOf(instance)  //true

3.谨慎定义方法
子类型覆盖超类型中的某个方法,或者是需要添加超类中不存在的方法,都需要
将给原型添加方法的代码放在继承之后(即替换原型的语句之后)

4.原型链问题
1) 通过原型来实现继承时,原型实际上会变成另一个类型的实例,原来的实例属性也就变成了现在的原型属性
2) 在创建子类型的实例时,不能向超类型的构造函数传递参数。
因此实践中很少会单独使用原型链

b.借用构造函数
也称 “伪造对象” 或 “经典继承”
在子类型构造函数的内部调用超类型构造函数。函数不过是在特定环境中执行代码的对象,因此通过apply(),call()方法可以在(将来)新建对象上执行构造函数,即在子类型对象上执行父类型函数中定义的所有对象初始化的代码。结果每个子类实例中都具有了父类型中的属性以及方法

        function Animal(name){            this.name = name;            this.colors = ["red","gray"];        }        function Dog(name){            //继承了Animal            Animal.call(this,name);            this.color = "gray";        }        Animal.prototype.sayName = function(){            alert(this.name);        }        var dog = new Dog("jake");        dog.colors.push("hhh");        console.log(dog);        var animal = new Animal();        console.log(animal);        dog.sayName();  //在超类型的原型中定义的方法,对于子类型而言是无法看到的

c.组合函数
也称”伪经典继承”,将原型链和借用构造函数的技术组合在一起。
原理是:使用原型链实现对原型属性和方法的继承,而通过借用构造函数实现对实例属性的继承。

        function Animal(name){            this.name = name;            this.colors = ["red","gray"];        }        function Dog(name){            //继承了Animal(属性)            Animal.call(this,name);            this.color = "gray";        }        Animal.prototype.sayName = function(){            alert(this.name);        }        //继承方法        Dog.prototype = new Animal();        Dog.prototype.constructor = Animal;        var dog = new Dog();        dog.colors.push("hhh");        console.log(dog);        var animal = new Animal();        console.log(animal);        dog.sayName();  //可以调用
原创粉丝点击