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);
_proto_保存继承自Object的方法。里面只有一个constructor属性指向Person()函数自身。
②当然我们是要用这个函数的,执行以下代码:
var per1 =new Person();
var per2 =new Person();
console.log(Person.prototype);
在创建实际对象时候,就会运行构造函数中的代码,而且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中动态原型模式。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。