6_2 创建对象

        // 虽然构造函数和对象字面量都可以用来创建对象,但这些方式都有一个明显的缺点:使用同一个接口创建很多对象,会产生大量的重复代码.为解决这个问题,人们开始使用工厂模式的一种变体。
        //工厂模式
        // 优点:解决了创建多个相似对象的问题,
        // 缺点:没有解决对象识别的问题(即怎样知道一个对象的类型)
        function createPerson(name,age,job){
            var o = new Object();
            o.name = name;
            o.age = age;
            o.job = job;
            o.sayName = function(){
                alert(o.name);
            };
            return o;
        }
        var person1 = createPerson('jerry',20,'honker');
        // person1.sayName();//jerry
        // console.log(typeof person1);//object
        console.log(person1 instanceof createPerson);
        
        
        //构造函数模式
        // ECMAScript中构造函数可以创建特定类型的对象,像object和Array这样的原生构造函数,在运行时会自动出现在执行环境中.从而定义自定义对象类型的属性和方法
        //要创建新实例,必须使用 new 操作符
        //缺点:就是每个方法都要在每个实例上重新创建一遍
        function Person(name,age,job){//按照惯例,构造函数始终都应该以一个大写字母开头,而非构造函数则应该以一个小写字母开头;为了区别于 ECMAScript 中的其他函数
            this.name = name;
            this.age = age;
            this.job = job;
            this.sayName = function(){
                alert(this.name);
            }
        };
        var person1 = new Person("Nicholas", 29, "Software Engineer");
        var person2 = new Person("Greg", 27, "Doctor");
        //person1 和 person2 分别保存着 Person 的一个不同的实例。这两个对象都有一个 constructor (构造函数)属性,该属性指向 Person
        //以这种方式定义的构造函数是定义在 Global 对象(在浏览器中是 window 对象)中的
        console.log(person1)
        console.log(person1.constructor == Person);//实例的constructor属性指向Person构造函数
        console.log(person1 instanceof Person);//检测对象类型
        
        
        //构造函数和其他函数的唯一区别就是调用的方式不同,构造函数也是函数,任何函数通过new来定义,那么他都可以称为构造函数
        var person = new Person("Nicholas", 29, "Software Engineer");//当做构造函数来使用
        // person.sayName(); //"Nicholas"
        
        Person("Greg", 27, "Doctor");//添加到window // 作为普通函数调用
        // window.sayName();//"Greg"
        
        var o = new Object();// 在另一个对象的作用域中调用
        Person.call(o,"Kristen", 25, "Nurse");
        // o.sayName();
        
        
        
        //原型模式
        // 创建的每一个函数都有一个prototype属性,这个属性是一个指针, 指向一个对象,而这个对象的作用是包含可以由特定类型的所有实例共享的属性和方法;
        function Person(){};//构造函数为空, 方法和所有属性直接添加到了 Person 的 prototype 属性中
        Person.prototype.name = "Nicholas";
        Person.prototype.age = 23;
        Person.prototype.job = "hunter";
        Person.prototype.sayName = function(){
            alert(this.name);
        }
        var person1 = new Person();
        // person1.sayName();//Nicholas
        var person2 = new Person();
        // person2.sayName();//Nicholas
        // alert(person1.sayName == person2.sayName) // true 新对象的这些属性和方法是由所有实例共享的
        console.log(Person);//ƒ Person(){} 构造函数
        console.log(Person.prototype);//{name: "Nicholas", age: 23, job: "hunter", sayName: ƒ, constructor: ƒ} 构造函数的原型对象
        console.log(Person.prototype.constructor);//ƒ Person(){} 原型对象中指向构造上函数的指针
        console.log(person1)//Person {} //构造函数创建的实例
        console.log(person1.__proto__)//实例内部指针, 指向构造函数的原型对象
        
        // isPortotypeof() 方法来检测实例 和 原型对象之间的关系
        console.log(Person.prototype.isPrototypeOf(person1));//true
        
        //getPrototypeOf() 方法来获取实例内部指针 指向的 原型对象的值
        console.log(Object.getPrototypeOf(person1).name);//Nicholas
        
        //每当有代码要读取某个对象的值时, 都会执行一次搜索,先从该对象的实例中查找, 如果找到则返回该属性的值,如果没找到继续像实例指向的原型对象中寻找,找到则返回该属性的值
        //虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例修改原型对象中的值,在实例中重新给一个属性赋值的话, 那么相对于在实例中创建了该属性, 该属性会屏蔽原型对象中的值
        function Person (){};
        Person.prototype.name = 'jerry';
        Person.prototype.age = 20;
        Person.prototype.job = 'hunter';
        
        var person1 = new Person();
        var person2 = new Person();
        person1.name = 'jack';//修改person1实例中name的值
        console.log(person1.name);//jack 实例中的name属性屏蔽了构造函数的原型对象中的name属性
        console.log(person2.name);//jerry 实例2 的name值还是获取原型对象中的值
        
        //delete 操作符 可以删除实例中的属性
        delete person1.name;//删除了person1实例中的name属性
        console.log(person1.name);//在person1中查询不到name值, 所以继续通过__proto__ 实例内部指针去构造函数原型对象中查找, 结果为jerry
        
        //hasOwnProperty 检测给定属性是否是存在在实例中,是属于实例的属性返回true , 否则返回false
        function Person(){};
        Person.prototype.name = 'Petter';
        Person.prototype.age = 12;
        
        var person1 = new Person();
        var person2 = new Person();
        
        console.log(person.hasOwnProperty('name'));//false
        person1.age = 30;
        console.log(person1.hasOwnProperty('age'));//true
        
        
        
        //in 操作符 : 判断能否通过对象访问到给定属性, 无论属性存在在实例中还是原型对象中, 都返回true
        function Person(){};
        Person.prototype.name = "Betty";
        Person.prototype.age = 16;
        Person.prototype.sayName = function(){
            alert(this.name);
        }
        
        var person1 = new Person();
        var person2 = new Person();
        
        // alert('name' in person1);//true
        console.log(person1.constructor instanceof Person)
        
        person1.name = 'Tom';
        // alert('name' in person1);//true
        // alert('father' in person1);//false 因为father属性即不存在于实例中, 也不存在于原型对象中
        // alert(person1.hasOwnProperty('name'));//true name存在与person1实例中
        
        //for-in 列举对象中可枚举的属性 , [[Enumerable]]特性为false 的属性不会被枚举出来
        var objNameArr = [];
        for(var item in person1){
            console.log(item);
            objNameArr.push(item);
        }
        console.log(objNameArr);// ["name", "age", "job", "sayName"]
        
        var objNameArr = [];
        for(var item in Person.prototype){
            console.log(item);
            objNameArr.push(item);
        }
        console.log(Person.prototype);//构造函数原型对象包含 name age job sayName 和 constructor
        console.log(objNameArr);// ["name", "age", "job", "sayName"] constructor的[[Enumerable]]特性为false ,所以不可枚举
        
        //要获取对象中可枚举的属性可以用Object.keys()方法
        var keys = Object.keys(Person.prototype);
        console.log(keys);// ["name", "age", "job", "sayName"]
        
        //如果要获取对象中的所有属性,无论可枚举和无可枚举 , 可以用方法Object.getOwnPropertyNames()方法
        var keys = Object.getOwnPropertyNames(Person.prototype);
        console.log(keys);//["constructor", "name", "age", "job", "sayName"] constructor 也会存在于数组当中
        
        //更简单的原型模式写法
        var Person = function(){};
        Person.prototype = {
            name :'jerry',
            age:20,
            job:'hunter',
            sayName:function(){
                alert(this.name);
            }
        }
        var person1 = new Person();
        console.log(Person.prototype.constructor);//ƒ Object() { [native code] } 构造函数的原型对象的constructor属性, 不在指向构造函数Person
        console.log(Person.prototype.contructor instanceof Person);//false 原型对象指针constructor不再指向构造函数Person; 如果constructor很重要,可以通过设置
        console.log(person1 instanceof Person) //true
        console.log(person1.constructor == Object);
        console.log(person1.constructor == Person);
        
        //设置constructor
        var Person = function(){};
        Person.prototype = {
            constructor:Person,
            name :'jerry',
            age:20,
            job:"hunter",
            sayName:function(){
                alert(this.name);
            }
        }
        console.log(Person.prototype.constructor == Person);//true 通过这种方式设置的constructor属性是可枚举的, [[Enumerable]]会被设置为true,默认情况下constructor属性是不可枚举的,可以使用Object.defineProperty()方法
        
        
        //原型的动态性
        function Friend(){};
        var girl = new Friend();
        Friend.prototype.sayHi = function(){//sayHi 方法是在创建实例后加的, 下方在实例中调用sayHi方法还是可以成功
            alert('hi');
        }
        // girl.sayHi();//hi 
        
        function Person(){};
        var friend = new Person();
        Person.prototype = {
            name:'jerry',
            age:20,
            job:'hunter',
            sayHi:function(){
                alert(this.name);
            }
        }
        console.log(friend.sayHi);//undefined
        console.log(Person.prototype);
        
        //原生对象的原型
        console.log(Array.prototype);
        
        //为原生对象添加新方法
        String.prototype.startWith = function(text){//不推荐
            return this.indexOf(text)==0;
        }
        var str = 'Hello World';
        console.log(str.startWith('Hello'));//true
        
        
        //组合使用构造函数模式和原型模式  使用度最高的模式
        // 组合模式:就是组合使用构造函数模式和原型模式; 构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性
        function Friend(name,age,job){
            this.name = name;
            this.age = age;
            this.job = job;
            this.firends = ["Shelby", "Court"];
        }
        Friend.prototype = {
            constructor:Friend,
            sayName:function(){
                alert(this.name);
            }
        }
        var firend1 = new Friend("Nicholas", 29, "Software Engineer");
        var firend2 = new Friend("Greg", 27, "Doctor");
        console.log(firend1.firends);
        firend1.firends.push('cao');
        console.log(firend1.firends);//["Shelby", "Court", "cao"] 自己的实例属性
        console.log(firend2.firends);//["Shelby", "Court"]
        // 虽然构造函数和对象字面量都可以用来创建对象,但这些方式都有一个明显的缺点:使用同一个接口创建很多对象,会产生大量的重复代码.为解决这个问题,人们开始使用工厂模式的一种变体。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352

推荐阅读更多精彩内容