JS创建对象

作者: 墨马 | 来源:发表于2017-09-21 17:09 被阅读21次

    工厂模式

    由于在ECMAScript无法创建类,所以用函数的封装以特定接口创建对象

    function creatPerson(name,age){
          var o = new Object();
          o.name = name;
          o.age = age;
          o.sayname = function(){
                 alert(this.name);
          }
          return o;
    }
    //创建实例
    var person = creatPerson("ice",22 );
    

    问题:解决了创建多个相似对象的问题,但是不知道对象的类型

    构造函数模式

    function Person(naem,age){
          this.name = name;
          this.age = age;
          this.sayname = function(){
                 alert(this.name);
          }
    }
    //创建实例
    var person = Person("ice",22 );
    

    与工厂模式相比较

    • 没有显示创建对象 ;
    • 将属性和方法赋予给this对象;
    • 没有return语句;

    经历的步骤
    1.创建一个对象;
    2.构造函数的作用域赋给新对象;
    3.执行构造函数的代码;
    4.返回新对象;

    alert(person instanceof Object); //ture 继承自Object
    alert(person instanceof Person); //ture
    //作为普通函数调用
    Person("ice",21);//添加到window对象
    alert(window.name);//ice
    //在另一个对象作用域中调用
    var o = new Object();
    Person.call(o,"ice",27);
    alert(o.name);//ice
    

    问题:不同实例,同名函数不相等,一个实例重新创建一遍函数

    原型模式

    创建一个函数,就会创建一个prototype属性(一个指向对象的指针)指向函数的原型对象;默认原型对象会获得一个constructor(构造函数)属性(共享的可以通过对象实例访问),包含一个指向prototype所在函数的指针;通过这个构造函数我们可以继续向原型对象添加其他属性和方法。创建自定义构造函数默认只会取到constructor属性,其余方法继承自Object

    alrt(Person.prototype.isPrototypeOf(person1));//true
    alrt(Object.getPrototypeOf(person1) == Person.prototype);//true
    

    通过isPrototypeOf确定对象之间是否存在这种关系

    alrt(Object.getPrototypeOf(person1) == Person.prototype);//true
    alrt(Object.getPrototypeOf(person1。name);//"Nicholas"
    

    通过getPrototypeOf返回对象的原型

    代码读取对象属性的时候会执行搜索,首先从实例本身开始,如果找到给定的属性,则返回属性的值;没有找到继续搜索指针指向的原型对象找到,返回属性的值。

    对象间关系
    function Person(){
    }
    Person.prototype.name = "Nicholas";
    Person.age = 29;
    Person.protype.job = "Software Enginner0"
    Person.prototype.sayName = function(){
       alert(this.name);
    };
    var Person1 = new Person();
    var Person2 = new Person();
    Person1 .name = "ice";
    alert(Person1 .name);//ice 来自实例
    alert(Person2 .name);//NIcholas 来自原型
    alert(Person1.sayname == Person2.sayname);//true
    

    我们为实例添加同名属性会屏蔽原型对象的同名属性,但不会修改。我们可以用delete删除实例属性重新访问原型的属性

    alert(Person1.hasOwnProperty("name"));//true
    

    用hasOwnProperty()(Object中继承)方法检测属性在实例中还是在原型中,当在实例中返回true

    示例
    示例
    示例

    单独实用"in"操作符无论在实例还是原型,可访问就返回true

    function hasprototyProperty(object,name){
       return !object.hasOwnProperty(name) && (name in object);
    }
    

    hasOwnProperty()方法和in操作符可以同时使用确定属性的位置


    for-in所有可以通过对象可访问可枚举的属性,以及屏蔽了原型中不可枚举的属性(有Enumerable标记的属性)都可以返回
    IE8之前屏蔽了原型中不可枚举的属性不会出现包括(hasOwnProperty()、propertyIsEnumerable()、toLocalString()、toString()、valueOf())

    Object.keys(Person.prototype);//获取 可枚举 属性字符串数组
    Object.keys(person);//获取  可枚举  的实例属性
    Object.getOwnPropertyNames(Person.prototype);获取  属性  字符串数组
    

    简单的原型语法

    function Person(){
    }
    Person.prototype = {
       name : "Nicholas",
       age : 29,
       job:"Software Engineer",
       sayName : function(){
          alert(this.name);  
       } 
    }
    

    将Person.prototype 设置为等于一个一对象字面量形式创建的新对象,结果相同,但是constructor不在指向Person

    重写原型对象之前
    重写原型对象之后
    此时instanceof还能返回正确结果,constructor已经无法确定对象类型了
    var newperson = new Person();
    
    alert(newperson instanceof Object);//true
    alert(newperson instanceof Person);//true
    alert(newperson.constructor == Object);//true
    alert(newperson.constructor == Person);//faluse
    

    必要时可以设置constructor 属性指向适当的值而此时constructor 的Enumerable被设置为true;

    function Person(){
    }
    Person.prototype = {
       constructor : Person,
       name : "Nicholas",
       age : 29,
       job:"Software Engineer",
       sayName : function(){
          alert(this.name);  
       } 
    }
    //实用与ECMAScript5兼容的浏览器
    Object.defineProperty(Person.prototype,"constructor",{
       enumerable : false,
       value : Preson
    })
    
    function Person(){
    }
    var friend  = new Person();
    Person.prototype = {
       constructor : Person,
       name : "Nicholas",
       age : 29,
       job:"Software Engineer",
       sayName : function(){
          alert(this.name);  
       } 
    }
    friend .sayName(); //error
    

    虽然可以随时为原型添加属性和方法并且在实例中反映出来,但是重写原型时,由于调用构造函数时添加的是指向最初原型的prototype指针,而把原型修改为另一个对象,切断了构造函数与最初原型的联系。
    实例中指针指向原型,不指向构造函数

    重写对象之前
    重写对象之后

    原生引用(Object、Array、String等等)都在构造函数原型上定义了方法

    alert(typeof Array.prototype.sort);//function
    alert(typeof String.prototype.substring);//function
    

    通过对象的原型不仅可以引用,也可以定义新方法
    但是这样容易命名冲突,但是这样容易意外重写原生方法
    如果原型中包含引用会出现问题
    例如:

    function Person(){
    }
    Person.prototype = {
       constructor : Person,
       name : "ice",
       friend : ["fire","purple"]
    }
    var person1 = new Person();
    var person2 = new Person();
    person1.friends.push("blue");
    alert(person1.friends);//"fire,purple,blue"
    alert(person2.friends);//"fire,purple,blue"
    alert(person1.friends  == person2.friends);//true
    

    组合使用构造函数模式和原型模式(创建自定义类型最常用的方法)

    函数构造模式用于定义实例属性,原型模式用于定义方法和共享属性

    function Person(name,age){
       this.name = name;
       this.age = age;
       this.friends = ["fire","red"];
    }
    Person.prototype = {
       constructor : Person,
       sayName : function(){
          alert(this.name);
       }
    }
    
    var person1 = new Person("ice","21");
    var person1 = new Person("blue","22");
    person1.friends.push("purple");
    alert(person1.friends);//"fire","red","purple"
    alert(person2.friends);//"fire","red"
    alert(person2.friends == person2.friends);//false
    alert(person2.sayName== person2.sayName);//true
    

    动态原型模式

    把所有信息都封装在构造函数中,通过在构造函数初始化原型,又保持同时使用构造函数和原型的优点。
    (通过检查某个应该存在的方法是否有效决定是否初始化原型)

    function Person(name,age){
       this.name = name;
       this.age = age;
       if(typeof this.sayName != "function"){
          Person.prototype.sayName = function(){
             alert(this.name);
          };
       }
    }
    
    var friend = new Person("ice",21);
    friend.sayName();
    

    只有在sayName()不存在的情况下(初次调用构造函数)才会添加到原型中,其中只需要检查一个待添加的属性或方法,而且可以通过instanceof操作符确定类型

    寄生构造函数模式

    创建一个函数,该函数的作用仅仅封装创建对象的代码,然后返回新创的对象
    例如创建一个具有额外方法的特殊数组,不能直接修改Array构造函数

    function SpecialArray(){
       var values = new Array();
       values.push.apply(values,arguments);
       values.toPipedString = function(){
          return this.ioni("|"); 
       }
       return values;
    }
    var colors = new SpecialArray("red","blue","green");
    alert(colors.toPipedString());//"red|blue|green"
    

    返回的对象与构造函数或构造函数的原型属性之间没有关系,因此不能依赖instanceof确定对象的类型。

    稳妥构造函数模式

    适用于安全环境,没有公共属性,禁止使用this和new,防止数据被其他应用程序改动时使用

    function Person(name,age){
       var o = new Object();
       //定义私有
       o.sayName = function(){
          alert(name); 
       }
       return o;
    }
    

    除了调用sayName()方法之外,没有别的可以访问数据成员的方式。也不能向构造函数的原始数据传入新数据适合安全环境,也不能使用instanceof操作符。

    相关文章

      网友评论

        本文标题:JS创建对象

        本文链接:https://www.haomeiwen.com/subject/qxihsxtx.html