封装类
1. 工厂模式
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
function createPerson(name, age){ var obj = new Object(); obj.name = name; obj.age = age; obj.sayName = function(){ console.log(this.name); // | console.log(obj.name) }; return obj; } var p1 = createPerson("ys", 12); var p2 = createPerson("ys", 12); console.log(p1); // { name: 'ys', age: 12, sayName: [Function] } console.log(p2); // { name: 'ys', age: 12, sayName: [Function] } console.log(p1 == p2); //false |
特点:
- 内部创建对象,外部返回,相当于调用函数,
- 对象无类型(比如其他oo语言,new一个对象,那个这个对象的构造函数就是对象类型)
2.构造函数模式
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function Person(name, age){ this.name = name; this.age = age; this.sayName = function(){ console.log(this.name); }; } var p1 = new Person("ys", 12); var p2 = new Person("ys", 12); console.log(p1); // { name: 'ys', age: 12, sayName: [Function] } console.log(p2); // { name: 'ys', age: 12, sayName: [Function] } console.log(p1 == p2); //false console.log(p1 instanceof Person); //true console.log(p2 instanceof Person); //true console.log(p1 instanceof Object); //true console.log(p2 instanceof Object); //true console.log(p1.constructor == Person); //true /*constructor属性为构造函数属性,指向构造函数Person*/ console.log(p2.constructor == Person); //true |
特点:
- 通过该模式创建的对象有自定义类型Person, 每个对象都是构造函数的实例
- 构造函数已经不再是意义上的调用函数,而是使用了new,构造过程包括四个步骤:
- ①创建一个新对象
- ②将构造函数的作用域赋给新对象(因此this指向了这个新对象)
- ③执行构造函数中的代码(为这个新对象添加属性)
- ④返回新对象
对于这样的构造函数模式,会发现有一点瑕疵,那就是sayName函数的功能是一样的,但是每个对象的实例都有该函数,这样却显得有点冗余,在此基础上,进行了一些改良:
0 1 2 3 4 5 6 7 8 9 10 |
function Person(name, age){ this.name = name; this.age = age; this.sayName = sayName; } function sayName(){ console.log(this.name); } |
将公共的函数部分,提取出来,作为全局函数,使得每个构造函数去调用他,达到了所有实例对象复用的效果。
通过不断的的学习,对构造函数模式有了新的理解,补充:
上面我写的构造函数是用函数声明的方式定义的,另一种方法,我们也可以用对象直接量方法声明
0 1 2 3 4 5 6 7 8 9 10 11 12 |
var Person = function(name, age){ this.name = name; this.age = age; this.sayName = function(){ console.log(this.name); }; } var p1 = new Person("ys", 12); var p2 = new Person("ys", 12); console.log(p1); // { name: 'ys', age: 12, sayName: [Function] } console.log(p2); // { name: 'ys', age: 12, sayName: [Function] } |
这样同样我得到了效果….但是最近看书学习,发现了一个问题,上面我这种方法(包括两种方法 )安全吗?
就连我之前都没有质疑过安全性,看看下面的代码
构造函数我就不写了.函数,对象直接量都是一个意思…
0 1 2 3 |
var p1 = Person("ys", 12); var p2 = Person("ys", 12); console.log(p1); // undefined console.log(p2); // undefined |
我们会发现竟然是undefined,怎么会,快找找原因….原因是他少了new这个关键字…
为什么会出现这样的原因呢,我们正确的结果,或许一看你就会了解。
0 1 2 3 4 5 6 |
var p1 = Person("ys", 12); var p2 = Person("ys", 12); console.log(p1); // undefined console.log(p2); // undefined console.log(window.name); //ys console.log(window.age); //12 |
原因就是没了new这个关键字,对于js的new关键字,大家可以这样理解:
new就是将函数内部的this的值,赋值给当前对象的this,如:this.name(实例对象) = this.name(构造函数)
当没有new的时候,this就变为了window,也就解释了。
那么问题又来了,有时候我们就是会忘记new,那这样的构造函数就显得不安全,这里有一个安全的构造函数模式,可以帮到你
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/*安全的构造函数模式*/ var Person = function(name, age){ if(this instanceof Person){ this.name = name; this.age = age; this.sayName = function(){ console.log(this.name); }; }else{ return new Person(name, age); } } var p1 = Person("ys", 12); var p2 = Person("ys", 12); console.log(p1); // { name: 'ys', age: 12, sayName: [Function] } console.log(p2); // { name: 'ys', age: 12, sayName: [Function] } console.log(window.name); // undefined console.log(window.age); // undefined |
3.原型对象模式
然后我们也觉得一个问题出现了,对于上面改良后的构造函数模式,所创建的全局函数sayName似乎成了Person构造函数的私人司机,只对于他一个人用,这样也就失去了全局函数的价值,而且当存在诸多构造函数时候,诸多的“sayName”也是一个问题,这个时候,原型模式完美的解决了这个问题
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//需要变动部分 function Person(name){ this.name = name; } //永久不变部分 Person.prototype.age = 12; Person.prototype.sayName = function(){ console.log(this.name); } var p1 = new Person("ys"); var p2 = new Person("ab"); console.log(p1.sayName()); //ys console.log(p1.age); //12 console.log(p2.sayName()); //ab console.log(p2.age); //12 console.log(p1.sayName == p2.sayName); //true |
当创建一个函数时候,该函数存在一个prototype属性,该属性是一个指针,指向一个对象,这个对象是一个方法和属性的集合,存储公共的属性和方法,达到所有实例共享的目的。
有全局对象的特性,区别于全局,Person构造函数的私人全局,只对它(Person)一个人生效。
当存在于对象实例时候,他们共享prototype里面的东西。