标签:出现 可见 地方 创建多个对象 shift 显示 作用 包含 不能
函数create()能根据接收的参数来构建一个包含所有必要信息的F对象。可无数次调用。
有个问题,怎么知道调用这个函数创建的对象是F对象呢?这个方法无法识别创建出来的对象的类型。
function createF(name,age) {
var tmp = new Object(); //创建一个新对象
tmp.name = name;
tmp.age = age;
tmp.sayName = function() {
console.log(this.name);
}
return tmp; //返回
}
var t1 = createF('try',19);
t1.sayName();
与上一种方式有什么不同?
要创建一个Person新实例,必须使用new操作符。事实上,任何函数只要通过new操作符来调用,那它就可以作为构造函数,构造函数如果不通过new来调用也就是普通函数。
会经历以下4个步骤:
创建自定义的构造函数意味着将来可以将它的实例表示为一种特定的类型,如p1是Person类型的。而这正是构造函数模式胜过工厂模式的地方。
function Person(name,age) {
this.name = name;
this.age = age;
this.sayName = function() {
console.log(this.name);
}
}
var p1 = new Person('try',19); //用new来创建对象
p1.sayName(); //try
var p2 = new Person('try',19);
console.log(p1.constructor == Person); //true
console.log(p2.constructor == Person); //true
//检测对象类型常用的还是instanceof,更可靠
console.log(p1 instanceof Person); //true
console.log(p2 instanceof Person); //true
console.log(p1 instanceof Object); //true
console.log(p2 instanceof Object); //true
?当然,也可以通过call() 或 apply()在某个特殊对象的作用域中调用构造函数。如Person.apply(p1,‘try‘);
,这是在对象p1的作用域中调用的,因此调用后
?就拥有量Person的所有属性和sayName方法(并不是所有方法,仅限于在构造函数中出现的,后面会讲原因)。
?构造函数有问题吗?按道理所有Person类型的实例的sayName方法都是一样的呀,但是构造函数里就不一样。
console.log(p1.sayName == p2.sayName); //false
创建两个完成相同任务的Function实例的确没有必要。那就可以向下面这样在构造函数外面定义一个新函数,再让构造函数里的函数等于它。这样一来,由于构造函数里的sayName包含的是一个指向函数的指针,因此p1 p2对象就共享了全局作用于中定义同一个这个函数。那么又有问题了,这样,还有封装性可言?
function Person() {
this.sayName = sayName;
}
function sayName() {
console.log(this.sayName);
}
?首先来解决,什么是原型?
?每创建一个函数,都会同时有一个prototype(原型)属性,这个属性是一个指针,指向prototype(原型)对象。与此同时,所有原型对象都会自动获得一个constructor(构造函数)属性,这也是一个指针,指向那个函数,如下图:
那么也就是,通过这个构造函数,我们可以继续为原型添加其他属性与方法。
??当把一个函数作为构造函数 (理论上任何函数都可以作为构造函数) 使用new创建对象的时候,那么这个对象就会存在一个默认的不可见的属性,来指向了构造函数的原型对象。 这个不可见的属性我们一般用 [[prototype]] 来表示,只是这个属性没有办法直接访问到。
一下几点要注意:
function Person(name,age) {
this.name = name;
this.age = age;
this.colors = ['red'];
}
Person.prototype.sayName = function() {
console.log(this.name);
}
var p1 = new Person('try',19);
p1.sayName(); //try
p1.name = 'aa';
var p2 = new Person('tt',19);
p2.sayName(); //tt
Person.prototype.sayAge = function() {
console.log(this.age);
}
p2.sayAge(); //19
但要注意,当原型对象指向另一个新的对象(包括字面量式的重写,因为这也是创建了一个新对象)时,constructor不再指向Person了;如下
console.log(Person.prototype.constructor); //Person
Person.prototype = {
name: 'ttt',
age: 30
}
console.log(Person.prototype.constructor); //Object
当然,如果必要(最好写上),可以特意在新对象中包含一个constructor属性并将其值设为Person,确保通过该属性能够访问到适当的值。
console.log(Person.prototype.constructor); //Person
Person.prototype = {
constructor: Person,
name: 'ttt',
age: 30
}
console.log(Person.prototype.constructor); //Person
与此相类似的
那么,如何判断一个属性是否存在于原型中:
如果一个属性存在,但是没有在对象本身中,则一定存在于原型中。
原型对象 | 构造函数 | |
---|---|---|
属性 | 共有,一经修改全部实例都会改变 | 每个实例独有一份 |
方法 | 所有实例公用方法 | 每个实例都有独立的,即便方法相同也要重新复制 |
缺陷 | 大家都是访问的同一个对象,如果一个对象对原型的属性进行了修改,则会反映到所有的对象上面 | 每个对象都有自己独有的一份,大家不会共享,造成内存的浪费和性能的低下。 |
function Person(name,age) {
this.name = name;
this.age = age;
this.sayAge = function() {
console.log(this.age);
}
}
var p1 = new Person('try','12');
Person.prototype.colors = ['red'];
Person.prototype.sayName = function() {
console.log(this.name);
}
// 原型对象的问题:
p1.colors.unshift('yellow');
var p2 = new Person('ttt','12');
//p1实例中修改的值,在p2中也显现了,共有
console.log(p2.colors); //yellow,red
//构造函数的问题:
console.log(p1.sayAge == p2.sayAge); //false
//p1 p2各有一份
这也是最最常用的方法。构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。
function Person(name,age) {
this.name = name;
this.age = age;
this.colors = [];
}
Person.prototype = {
constructor: Person, //重写原型对象切断了联系 要指回来 不然这个属性没法用了
sayName: function() {
console.log(this.name);
},
sayAge: function() {
console.log(this.age);
}
}
var p1 = new Person('a',19);
var p2 = new Person('b',20);
console.log(p2.colors); //[]
p1.colors.push('yellow');
console.log(p2.colors); //[]
console.log(p1.sayName == p2.sayName); //true
将所有信息都封装在了构造函数中,通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型的有点。换句话说,可以通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型。但注意使用动态原型时,不能使用对象字面量重写原型,因为如果在已经创建了实例的情况下重写原型,那么就会切断现有实例和新原型之间的联系。
function Person() {
this.name = 't';
this.age = 19;
if(typeof this.sayName != 'function') {
//if不必一一检查所有属性和方法,只需检查初始化后应该存在的任何属性和方法即可
Person.prototype.sayName = function() {
console.log(this.name);
}
Person.prototype.sayAge = function() {
console.log(this.age);
}
}
}
var p1 = new Person(); //初次调用构造函数
var p2 = new Person(); //不是初次了,if内的语句不会执行,因为这时候原型已完成初始化
参考《JavaScript高级程序设计第3版》。
标签:出现 可见 地方 创建多个对象 shift 显示 作用 包含 不能
原文地址:https://www.cnblogs.com/TRY0929/p/11870385.html