js 创建对象的几种方法
1、 使用object创建
var person = new Object();
person.name = "Tom";
person.age = "29";
person.job = "software engineer";
person.sayName = function(){
console.log(this.name);
} console.log(typeof person); // object
console.log(person instanceof Object); //true
2、 字面量对象
var person = {
name: "Tom",
age:29,
job:"software engineer",
sayName:function(){
console.log(this.name);
}
}
console.log(typeof person); // object
console.log(person instanceof Object); //true
使用字面量创建对象比使用object创建直观一些。这两种创建对象的方式都有明显的缺点:使用同一个接口创建很对对象,会产生大量的重复代码
3、 工厂模式
function createPerson(name,age,job){
var o = new Object();
o.name = name;
o.job = job;
o.age = age;
o.sayName = function(){
console.log(this.name);
}
return o;
} var p1 = createPerson("Tom",29,"software engineer");
var p2 = createPerson("Jerry",32,"doctor"); console.log(typeof p1); // object
console.log(p1 instanceof createPerson); // false
工厂模式,可以使用同一种接口创建多个对象,且很简洁。但也有一个问题:无法确定该对象实例属于哪种对象类型(instanceof 无效)。
4、构造函数模式
function Person(name,age,job){
this.name = name;
this.job = job;
this.age = age;
this.sayName = function(){
console.log(this.name);
}
} var p1 = new Person("Tom",29,"software engineer");
var p2 = new Person("Jerry",32,"doctor"); console.log(typeof p1); // object
console.log(p1 instanceof Person); // true
console.log(p1 instanceof Object); // true
console.log(p1.constructor == Person); // true p1.sayName(); //Tom //构造函数当作普通函数来使用
Person("jack",30,"driver");
window.sayName(); // jack // 在另一个对象的作用域中使用
var o = new Object();
Person.call(o,"Kristen",25,"Nurse");
o.sayName() // Kristen
Person() 函数没有显示地创建对象,直接将属性和方法赋给了this对象,没有 return 语句。
使用 new 操作符创建新的对象实例,调用构造函数实际上会经过以下步骤:创建一个新对象,将构造函数的作用域赋给新对象(this指向这个新对象),执行构造函数中的代码(为新对象添加属性),返回新对象。
构造函数也是函数,也可以正常调用。
构造函数的缺点是:每个的方法都要在每个对象实例上重新创建一遍,上面创建的p1 、p2都有一个sayName()的方法,但这两个方法不是同一个Function的实例,因为每定义一个函数就是实例化了一个对象
function Person(name,age,job){
this.name = name;
this.job = job;
this.age = age;
this.sayName = new Function("console.log(this.name);"); //逻辑上与声明函数是等价的,并且每创建一个对象就要执行一次
} var p1 = new Person("Tom",29,"software engineer");
var p2 = new Person("Jerry",32,"doctor"); console.log(p1.sayName == p2.sayName); // false
当然为了构造函数创建对象时,每个函数都是同一个Function实例,也可以使用全局函数:
function Person(name,age,job){
this.name = name;
this.job = job;
this.age = age;
this.sayName = sayName; // 使用全局函数
} function sayName(){
console.log(this.name);
} var p1 = new Person("Tom",29,"software engineer");
var p2 = new Person("Jerry",32,"doctor"); console.log(p1.sayName == p2.sayName); // true
但是这样,如果有很多函数,就要定义很多全局函数,没有封装性
5、原型模式
每个函数都有一个 prototype 属性,一个指向某个对象(原型对象)的指针,原型对象中包含着所有实例共享的属性和方法。那么就可以使用原型来新建对象
function Person(){
}
Person.prototype.name = "Tom";
Person.prototype.job = "software engineer";
Person.prototype.friends = ["Shelby","Court"];
Person.prototype.age = 29;
Person.prototype.sayName = function (){
console.log(this.name);
}; var p1 = new Person();
var p2 = new Person(); p1.friends.push("Van"); p1.sayName(); // Tom
p2.sayName(); // Tom console.log(p1.friends); // "Shelby,Court,Van"
console.log(p2.friends); // "Shelby,Court,Van"
console.log(p1.friends == p2.friends); // true
console.log(p1.sayName == p2.sayName); // true
很明显,单独使用原型新建对象时,不能传递参数,并且会因为所有对象的数据都一样而不能添加某个对象自己的特性
6、构造函数和原型模式的组合模式
function Person(name,age,job){
this.name = name;
this.job = job;
this.age = age;
this.friends = ["Shelby","Court"];
}
Person.prototype.sayName = function (){
console.log(this.name);
}; var p1 = new Person("Tom",29,"software engineer");
var p2 = new Person("Jerry",32,"doctor"); p1.friends.push("Van"); p1.sayName(); // Tom
p2.sayName(); // Jerry console.log(p1.friends); // "Shelby,Court,Van"
console.log(p2.friends); // "Shelby,Court"
console.log(p1.friends == p2.friends); // false
console.log(p1.sayName == p2.sayName); // true
这是一种常用模式
也可以对其进行一些修改:
function Person(name,age,job){
this.name = name;
this.job = job;
this.age = age;
this.friends = ["Shelby","Court"]; if(this.sayName != "function"){
Person.prototype.sayName = function (){
console.log(this.name);
};
}
}
现在自身属性和原型的初始化,都封装在构造函数中,看起来更像面向对象。这样的写法下,不能使用对象字面量重写原型,因为对象字面重写原型不会让现有实例和新原型联系起来,与现有实例联系的还是旧原型。
最新文章
- 【转】easyui $.message.alert 点击右上角的关闭按钮时,不执行定义的回调函数
- 1.1---判断字符串是否所有字符都不相同(CC150)
- projecteuler 10001st prime (求出第10001个质数)
- 【题解】【数组】【Prefix Sums】【Codility】Genomic Range Query
- uva301 - Transportation
- C3p0/元数据/内省-Bean/自定义查询封装类/查询/分页
- OpenReports操作指南
- C#获取QQ旋风的下载记录
- CCBValue
- HDU1577-WisKey的眼神
- http请求的完整过程
- Java知IO
- 文本离散表示(二):新闻语料的one-hot编码
- [IR] Arithmetic Coding
- a 链接点击下载
- memcached 内存初始化与key-value存储
- maven分别打包开发、生产配置文件
- kubenetes--Namespace命名空间
- Kafka集群环境搭建(2.9.2-0.8.2.2)
- Tensorflow源码编译,解决tf提示未使用SSE4.1 SSE4.2 AVX警告【转】