• JS面相对象


    一、理解对象:
    
    //第一种:基于Object对象
    var person = new Object();
    person.name = 'My Name';
    person.age = 18;
    person.getName = function(){
           return this.name;
    }
    
    //第二种:对象字面量方式(比较清楚的查找对象包含的属性及方法)
    var person = {
           name : 'My name',
           age : 18,
           getName : function(){
                 return this.name;
           }
    }
    
    //JS的对象可以使用.操作符动态的扩展其属性,可以使用delete操作符或将属性值设置为undefined来删除属性:
    person.newAtt=“new Attr”;    //添加属性
    alert(person.newAtt);        //new Attr
    delete person.age;
    alert(person.age);            //undefined(删除属性后值为undefined);
    
    二、对象属性类型
    
    //ECMA-262第5版定义了JS对象属性中特征(用于JS引擎,外部无法直接访问)。ECMAScript中有两种属性:数据属性和访问器属性
    
    1、数据属性:
    
    //  configurable:    表示能否使用delete操作符删除从而重新定义,或能否修改为访问器属性。默认为true;
    //  enumberable:    表示是否可通过for-in循环返回属性。默认true;
    //  writable:        表示是否可修改属性的值。默认true;
    //  value:            包含该属性的数据值。读取/写入都是该值。默认为undefined;如上面实例对象person中定义了name属性,其值为’My name’,对该值的修改都反正在这个位置
    //    调用Object.defineProperty()方法,它接收三个参数:属性所在对象,属性名和一个描述符对象
    
    var person = {};
    Object.defineProperty(person, 'name', {
          configurable: false,
          writable: false,
          value: 'Jack'
    });
    alert(person.name);    //Jack
    delete person.name;
    person.name = 'lily';
    alert(person.name);    //Jack
    //    值得注意的是一旦将configurable设置为false,则无法再使用defineProperty将其修改为true
    
    2、访问器属性:
    
    //    它主要包括一对getter和setter函数,在读取访问器属性时,会调用getter返回有效值;写入访问器属性时,调用setter,写入新值;该属性有以下4个特征:
    //    configurable:是否可通过delete操作符删除重新定义属性;
    //    numberable:是否可通过for-in循环查找该属性;
    //    get:读取属性时调用,默认:undefined;
    //    set:写入属性时调用,默认:undefined;
    
    //    访问器属性不能直接定义,必须使用defineProperty()来定义,如下:
    var person = {
          _age: 18
    };
    Object.defineProperty(person, 'isAdult', {
          get: function(){
                if(this._age >= 18){
                    return true;
                }else{
                    return false;
                }
         }
    });
    alert(person.isAdult?'成年':'未成年');  //成年
    //     这里isAdult的值,是要通过函数来判断的,如果写value,后面返回的是函数体。所以通过get来设置
    //    可知,定义访问器属性时getter与setter函数不是必须的,并且,在定义getter与setter时不能指定属性的configurable及writable特性;
    
    //    Object.defineProperties()方法可以用来一次性定义多个属性的特性:
    var person = {};
    Object.defineProperties(person,{
          _age:{
               value:19
          },
          isAdult:{
               get: function () {
                     if(this._age >= 18){
                            return true;
                      }else{
                            return false;
                      }
               }
          }
    });
    alert(person.isAdult?'成年':'未成年');//成年
    //    上述代码使用Object.defineProperties()方法同时定义了_age及isAudlt两个属性的特性
           
    
    3、获取属性特性:
    
    //    此外,使用Object.getOwnPropertyDescriptor()方法可以取得给定属性的特性:
    var descriptor = Object.getOwnPropertyDescriptor(person,'_age');
    console.log(descriptor);
    //Object {value: "19", writable: false, enumerable: false, configurable: false}
    三、创建对象
    
    //使用Object构造函数或对象字面量都可以创建对象,但缺点是创建多个对象时,会产生大量的重复代码,因此下面介绍可解决这个问题的创建对象的方法
    
    1、工厂模式
    
    function createPerson(name, age, job) {
            var o    = new Object();
            o.name    = name;
            o.age    = age;
            o.job    = job;
            o.getName = function () {
                return this.name;
            }
             return o;//使用return返回生成的对象实例
    }
    var person = createPerson('Jack', 19, 'SoftWare Engineer');
    //创建对象交给一个工厂方法来实现,可以传递参数,但主要缺点是无法识别对象类型,因为创建对象都是使用Object的原生构造函数来完成的。
    
    2、构造函数模式
    
    function Person(name,age,job){
            this.name = name;
            this.age = age;
            this.job = job;
            this.getName = function () {
                return this.name;
            }
    }
    var person1 = new Person('Jack', 19, 'SoftWare Engineer');
    var person2 = new Person('Liye', 23, 'Mechanical Engineer');
    
        //    使用自定义的构造函数(与普通函数一样,只是用它来创建对象),定义对象类型(如:Person)的属性和方法。它与工厂方法区别在于:
        //    1.没有显式地创建对象
        //    2.直接将属性和方法赋值给this对象;
        //    3.没有return语句;
        //    4.此外,要创建Person的实例,必须使用new关键字,以Person函数为构造函数,传递参数完成对象创建;实际创建经过以下4个过程:
    
        //    a.创建一个对象
        //    b.将函数的作用域赋给新对象(因此this指向这个新对象,如:person1)
        //    c.执行构造函数的代码
        //    d.返回该对象
        //    上述由Person构造函数生成的两个对象person1与person2都是Person的实例,因此可以使用instanceof判断,并且因为所有对象都继承Object,因此person1 instanceof Object也返回真:
        
        //    instanceof判断是否是一个类的实例
        alert(person1 instanceof Person);//true;
        alert(person2 instanceof Person);//true;
        alert(person1 instanceof Object);//true;
        alert(person1.constructor === person2.constructor);//ture;
    
    //    虽然构造函数方式比较不错,但也存在缺点,那就是在创建对象时,特别针对对象的属性指向函数时,会重复的创建函数实例,以上述代码为基础,可以改写为:
    function Person(name,age,job){
            this.name      = name;
            this.age      = age;
            this.job      = job;
            this.getName = new Function () {//改写后效果与原代码相同,不过是为了方便理解
                return this.name;
            }
    }
    //上述代码,创建多个实例时,会重复调用new Function();创建多个函数实例,这些函数实例还不是一个作用域中,当然这一般不会有错,但这会造成内存浪费。当然,可以在函数中定义一个getName = getName的引用,而getName函数在Person外定义,这样可以解决重复创建函数实例问题,但在效果上并没有起到封装的效果,如下所示:
    function Person(name,age,job){
            this.name     = name;
            this.age     = age;
            this.job     = job;
            this.getName = getName;
    }
    function getName() {
            return this.name;
    }
       
    
    3、原型模式
    
    //    JS每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,它是所有通过new操作符使用函数创建的实例的原型对象。原型对象最大特点是,所有对象实例共享它所包含的属性和方法,也就是说,所有在原型对象中创建的属性或方法都直接被所有对象实例共享。
    
    function Person(){};
    Person.prototype.name = 'Jack';//使用!!!原型!!!来添加属性
    Person.prototype.age = 29;
    Person.prototype.getName = function(){
         return this.name;
    }
    var person1 = new Person();
    alert(person1.getName());//Jack
    var person2 = new Person();
    alert(person1.getName === person2.getName);//true;共享一个原型对象的方法
    //    实例属性或方法的访问过程是一次搜索过程:
    //    1.首先从对象实例本身开始,如果找到属性就直接返回该属性值;
    //    2.如果实例本身不存在要查找属性,就继续搜索指针指向的原型对象,在其中查找给定名字的属性,如果有就返回;
    //    基于以上分析,原型模式创建的对象实例,其属性是共享原型对象的;但也可以自己实例中再进行定义,在查找时,就不从原型对象获取,而是根据搜索原则,得到本实例的返回;简单来说,就是实例中属性会屏蔽原型对象中的属性;
    
    //    原型与in操作符
    //    一句话:无论原型中属性,还是对象实例的属性,都可以使用in操作符访问到;要想判断是否是实例本身的属性可以使用object.hasOwnProperty(‘attr’)来判断;
    
    //    原生对象中原型
    //    原生对象中原型与普通对象的原型一样,可以添加/修改属性或方法,如以下代码为所有字符串对象添加去左右空白原型方法:
    
    String.prototype.trim = function(){
            return this.replace(/^s+/,'').replace(/s+$/,'');
    }
    var str = '   word space   ';
    alert('!'+str.trim()+'!');//!word space!
    
    //原型模式的缺点,它省略了为构造函数传递初始化参数,这在一定程序带来不便;另外,最主要是当对象的属性是引用类型时,它的值是不变的,总是引用同一个外部对象,所有实例对该对象的操作都会其它实例:
    function Person() {}
    Person.prototype.name      = 'Jack';
    Person.prototype.lessons = ['Math','Physics'];
    var person1 = new Person();
    person1.lessons.push('Biology');
    var person2 = new Person();
    alert(person2.lessons);    //    Math,Physics,Biology,person1修改影响了person2
  • 相关阅读:
    表格边框
    vue路由守卫
    移动端专用css
    原生js写的的浏览器历史记录
    有趣
    表格边框
    路由
    php安装
    curl
    case when
  • 原文地址:https://www.cnblogs.com/nemoro1928/p/5380080.html
Copyright © 2020-2023  润新知