2

js创建对象有很多方法,以下是常见方法整理。

ES5创建对象

工厂模式

function person (name, age, sex) {
    var O = new Object();
    O.name = name;
    O.age = age;
    O.sex = sex;
    O.sayName =function(){
        console.log(this.name);
    }
    return O;
}
var per = person("per",10,"male"); //不需要用new,因为有return,就是个普通函数,很好理解
console.log(per instanceof person); //false

构造函数模式

function Person (name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.sayName =function(){
        console.log(this.name);
    }
}
var per =new Person("per",10,"male"); 
console.log(per instanceof Person); //true

分析创建过程,

 var per =new Person("per",10,"male"); 

在这行代码执行时,四个步骤:
①出现了一个空的对象
②this指向这个对象
③执行构造函数的代码
④把这个对象取个名字是per,per的指针就指向这个对象,于是可以通过per操作这个对象

工厂模式定义出的对象,instanceof识别不出是"person类"。
构造函数模式,每次new一个对象,里面的函数都会创建一次,就这个sayName函数,明明共有同一个就可以了。
解决这个问题,出现了原型模式:

原型模式

function Person () {
    Person.prototype.name = "p1";
    Person.prototype.age = 10;
    Person.prototype.sex = "female";
    Person.prototype.sayName =function(){
        console.log(this.name);
    }
}

那么,这些代码干了什么呢?
①当你创建Person()函数后,就会有一个prototype属性随之而来
我们可以看看,这个prototype是什么,执行以下代码:

 console.log(Person.prototype);

clipboard.png

_proto_保存继承自Object的方法。里面只有一个constructor属性指向Person()函数自身。
②当然我们是要用这个函数的,执行以下代码:

var per1 =new Person();
var per2 =new Person();
console.log(Person.prototype);

clipboard.png

在创建实际对象时候,就会运行构造函数中的代码,而且per1、per2两个对象,就会执行两次构造函数的代码,但并不会多创建一个Person的prototype属性,只是重新赋值里面的name、age、sex和sayName变量。
③per1和per2有各自的prototype属性,指向Person的prototype属性。可以简单理解为per1、per2各自的"指针"指向同一个"对象"。

这个原型模式啊,就真的好像单例模式了,每个创建的对象都在操作同一个对象。

最优:动态原型模式

function Person (name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    if(typeof this.sayName != "function"){  
        Person.prototype.sayName = function(){
            console.log(this.name);
        }
        Person.prototype.sayAge = function(){
            console.log(this.age);
        }
    }
}
var per = new Person("wlq", 19, "man");

这样的代码,使得每个对象的name、age、sex都是各自的(不共有),然后函数写在原型上,就又是共享的,很不错。还有个地方,if语句的判断,使得第二次创建对象时候,不会重新给Person.prototype.sayName和Person.prototype.sayAge重赋值。


原型重写的问题

function Person (name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    if(typeof this.sayName != "function"){
        Person.prototype.sayName = function(){
            console.log(this.name);
        }
    }
}
function WPerson (name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    if(typeof this.sayName != "function"){
        WPerson.prototype = {   //这里进行了原型的重写
            constructor: WPerson,
            sayName: function(){
                console.log(this.name);
            }
        }
    }
}
var per1 = new Person("w", 19, "man");
var per2 = new WPerson("q", 18, "man");
var per3 = new WPerson("q", 18, "man");
per1.sayName();  //输出w
per2.sayName();  //报错,说没有sayName这个方法
per3.sayName();  //输出q
console.log(per2.name);  //输出q

原因

重写原型的发生是在创建对象之后的,per2指向的WPerson的原型上面只有name、age、sex,再创建完per2后,才执行WPerson原型的重写,per3甚至以后创建的WPerson类型对象就都会有sayName函数了。

改进方法

方法一(通过先执行一次WPerson的原型重写):

function WPerson (name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;       
}
WPerson.prototype = {  //写在创建对象之前
    constructor:WPerson,
    sayName: function(){
        console.log(this.name);
    }
}
var per = new WPerson("q", 18, "man");
per.sayName();  //输出q

方法二(提前先执行一次new):

   function WPerson (name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;  
        if(typeof this.sayName != "function"){
            WPerson.prototype = {  
                constructor:WPerson,
                sayName: function(){
                    console.log(this.name);
                }
            };
            return new WPerson(name,age,sex);  //初次运行时,多调用一次new
           }
    }     
    var per = new WPerson("q", 18, "man");
    per.sayName();  //输出q
   


ES6中的class

class Point{
  constructor(x, y) {    //相当于java中的构造函数,如果不写默认为空
    this.x = x;          //x,y定义在对象自身上面
    this.y = y;
  }
  add() {                //该方法定义在Point.prototype上
    console.log(this.x + this.y);
  }
}
var p = new Point(2, 3);
p.add();  //输出5

可以说,class用法就是ES5中动态原型模式。


你才到碗里去
40 声望1 粉丝

多看书就对了。