#Javascript是“基于prototype的语言 ”,且无法通过类来创建对象;
可以通过以下6种方式创建对象
一.字面式创建
方法:将成员信息写到{}中,赋值给一个变量,此时这个变量就是一个对象。
1.1定义方式
(1)采取键值对的形式
var 变量 { 属性:属性值,属性:属性值,…}
// 1.利用对象字面量创建对象 {}
// var obj = {}; // 创建了一个空的对象
var obj = {
uname: '张三疯',
age: 18,
sex: '男',
sayHi: function() {
console.log('hi~');
}
}
// (1) 里面的属性或者方法我们采取键值对的形式 键 属性名 : 值 属性值
// (2) 多个属性或者方法中间用逗号隔开的
// (3) 方法冒号后面跟的是一个匿名函数
// 2. 使用对象
// (1). 调用对象的属性 我们采取 对象名.属性名 . 我们理解为 的
console.log(obj.uname);
// (2). 调用属性还有一种方法 对象名['属性名']
console.log(obj['age']);
// (3) 调用对象的方法 sayHi 对象名.方法名() 别忘记添加小括号
obj.sayHi();
二、 new + Object创建对象
方法:先通过object构造器new一个对象,再往里丰富成员信息。
2.1定义方式
*(1)利用 等号 = 赋值的方法
(2)属性和方法之间用 分号结束*
// 利用 new Object 创建对象
var obj = new Object(); // 创建了一个空的对象
obj.uname = '张三疯';
obj.age = 18;
obj.sex = '男';
obj.sayHi = function() {
console.log('hi~');
}
// (1) 我们是利用 等号 = 赋值的方法 添加对象的属性和方法
// (2) 每个属性和方法之间用 分号结束
console.log(obj.uname);
console.log(obj['sex']);
obj.sayHi();
【】以上两种方法在使用同一接口创建多个对象时,会产生大量重复代码,为了解决此问题,工厂模式被开发*
三、 工厂模式
方法:使用一个函数来创建对象
3.1定义方式
- 将对象构建的过程封装在一个函数中,这个函数能创建一个对象,
并为他进行初始化赋值 ,最后返回这个对象;若要新建对象,直接调用这个函数即可。- 这种方式是使用一个函数来创建对象,减少重复代码,解决了前面三种方式的代码冗余的问题,但是方法不能共享的问题还是存在。
(1) 我们是利用 等号= 赋值的方法 添加对象的属性和方法
(2) 每个属性和方法之间用 分号结束
// 使用工厂模式创建对象
// 定义一个工厂方法
function creatPerson(name,age) {
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function () {
alert('this.name');
}
return o;
}
var o1 = creatPerson('zhang',12);
var o2 = creatPerson('js',12);
//缺点:调用的还是不同的方法,浪费内存
//没有解决对象识别的问题,因为全部都是Object
//优点:解决了代码重复实例化多个对象的问题,逻辑简单
alert(o1.sayName === o2.sayName); //false
alert(o1 instanceof Object);// true
本例中,得到的都是o对象,对象的类型都是Object,因此出现了构造函数模式
四、 构造函数创建对象
方法:创建一个新对象
将构造函数的作用域赋给新对象(将this指向这个新对象)
执行构造函数代码(为这个新对象添加属性)
返回新对象
4.1 定义方式
# function 构造函数名() {
this.属性 = 值;
this.方法 = function() {}
} new 构造函数名();
(1) 构造函数名字首字母要大写 (见函数名首字母大写必为构造函数)
(2) 属性和方法前面必须添加 this
(3) 构造函数不需要return
function Star(uname, age, sex) {
this.name = uname;
this.age = age;
this.sex = sex;
this.sing = function(sang) {
console.log(sang);
}
}
var ldh = new Star('刘德华', 18, '男'); // 调用函数返回的是一个对象
// console.log(typeof ldh);
console.log(ldh.name);
console.log(ldh['sex']);
ldh.sing('冰雨');
var zxy = new Star('张学友', 19, '男');
console.log(zxy.name);
console.log(zxy.age);
zxy.sing('李香兰')
// 1. 构造函数名字首字母要大写
// 2. 我们构造函数不需要return 就可以返回结果
// 3. 我们调用构造函数 必须使用 new
// 4. 我们只要new Star() 调用函数就创建一个对象 ldh {}
// 5. 我们的属性和方法前面必须添加 this
对比工厂模式有以下不同之处:
1、没有 return 语句
2、直接将属性和方法赋给了 this 对象
3、工厂函数针对的都bai是Object的对象模型,而构造函数可以匹配du定义的对象模型
4.构造函数弊端,如果在全局中定义相同的局部变量,容易造成全局污染,因为this.xx如果在局部获取不到,就会去全局中获取
5.构造函数可以重写,可以在全局中添加新属性和方法
Person.prototype = {},但工厂函数只能在局部添加
#优点:实例对象中的constructor属性指向了它的构造函数,proto属性指向了它的原型对象,因此完全可以确定该对象的类型。
确定对象类型的两种方式:
(推荐): 对象 instanceof 构造函数 (返回true/false)
(不推荐): 对象.constructor(直接获取其构造函数对象)
#缺点 :对象中所有的函数都需要重复定义,浪费内存
可以看出,构造函数知道自己从哪里来(通过 instanceof 可以看出其既是Object的实例,又是Person的实例)
构造函数也有其缺陷,每个实例都包含不同的Function实例( 构造函数内的方法在做同一件事,但是实例化后却产生了不同的对象,方法是函数 ,函数也是对象)
五、原型模式
方法:每个方法中都有一个原型(prototype),每个原型都有一个构造器(constructor),构造器又指向这个方法。
function Animal(){} alert(Animal.prototype.constructor==Animal);//true
5.1定义方式
#通过原型创建对象,把属性和方法绑定到prototype上;
#通过这种方式创建对象,方法是共享的,每个对象调用的是同一个方法。
function Person() {
}
Person.prototype.name = "lisi";
Person.prototype.age = 21;
Person.prototype.family = ["lida","lier","wangwu"];
Person.prototype.say = function(){
alert(this.name);
};
console.log(Person.prototype); //Object{name: 'lisi', age: 21, family: Array[3]}
var person1 = new Person(); //创建一个实例person1
console.log(person1.name); //lisi
var person2 = new Person(); //创建实例person2
person2.name = "wangwu";
person2.family = ["lida","lier","lisi"];
console.log(person2); //Person {name: "wangwu", family: Array[3]}
// console.log(person2.prototype.name); //报错
console.log(person2.age); //21
//优点:由于原型对象被同一类型的所有对象共享,
//因此可以将函数 和 共享变量 定义在原型上,
//从而能避免重复创建对象,节约内存空间,并且能实现变量的共享。
//缺点:也正是因为原型拥有被同一类型的所有对象共享的特点,
// 因此如果将所有属性都定义在原型上,那么就不存在对象的实例属性了
#原型模式的好处是所有对象实例共享它的属性和方法(即所谓的共有属性),此外还可以如代码第16,17行那样设置实例自己的属性/方法(即所谓的私有属性),可以覆盖原型对象上的同名属性/方法。
六、构造函数+原型模式PRO(动态原型模式)
# 解决了原型模式的“破坏了封装性”的问题的
# 构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性
6.1定义方式
function Person(name,age,family){
this.name = name;
this.age = age;
this.family = family;
}
Person.prototype = {
constructor: Person, //每个函数都有prototype属性,指向该函数原型对象,原型对象都有constructor属性,这是一个指向prototype属性所在函数的指针
say: function(){
alert(this.name);
}
}
var person1 = new Person("lisi",21,["lida","lier","wangwu"]);
console.log(person1);
var person2 = new Person("wangwu",21,["lida","lier","lisi"]);
console.log(person2);
优点:和原型模式+构造函数模式相比,增加了封装性,更利于理解代码。
缺点:完美无缺