想成为网站设计师要怎么做,深圳关键词排名seo,淄博网站备案公司,销售新品牌如何推广1. 工厂模式 这种模式抽象了创建具体对象的过程#xff0c;用函数来封装以特定接口创建对象的细节 缺点#xff1a;没有解决对象识别的问题#xff08;即怎样知道一个对象的类型#xff09; function createPerson(name, age, job) {var o new Object();o.name name;o.ag…1. 工厂模式 这种模式抽象了创建具体对象的过程用函数来封装以特定接口创建对象的细节 缺点没有解决对象识别的问题即怎样知道一个对象的类型 function createPerson(name, age, job) {var o new Object();o.name name;o.age age;o.job job;o.sayName function() {alert(this.name)};return o;
}
const personOne createPerson(lee, 29, Software Engineer)
const personTwo createPerson(Gred, 24, Doctor) 2. 构造函数模式 1与工厂模式相比构造函数模式 没有显示地创建对象直接将属性和方法赋值给了this对象没有return语句区别于非构造函数构造函数以大写字母开头 2要创建Person的新实例必须使用new操作符。 以这种方式调用构造函数实际上会经历以下4个步骤 创建一个新对象将构造函数的作用域赋给新对象因此this就指向了这个新对象执行构造函数的代码为这个新对象添加属性 返回新对象 function Person(name, age, job) {this.name name;this.age age;this.job job;this.sayName function() {alert(this.name)};
}
const personOne new Person(lee, 29, Software Engineer)
const personTwo new Person(Gred, 24, Doctor) 3personOne和personTwo分别保存着Person的一个不同的实例。这两个对象都有一个constructor(构造函数)属性该属性指向Person console.log(personOne.constructor Person) // true
console.log(personTwo.constructor Person) // true 4以上例子中创建的所有对象既是Object的实例同时也是Person的实例这一点通过instanceof操作符可以得到验证。 console.log(personOne instanceof Person) // true
console.log(personOne instanceof Object) // true
console.log(personTwo instanceof Person) // true
console.log(personTwo instanceof Object) // true 5构造函数毕竟也是函数不存在定义构造函数的特殊语法。任何函数只要通过new操作符来调用那它就可以作为构造函数而任何函数如果不通过new操作符来调用那它跟普通函数也不会有什么两样。 // 当作构造函数使用
const person new Person(lee, 29, Software Engineer);
person.sayName(); // lee// 作为普通函数调用
Person(Gred, 24, Doctor) // 添加到window
window.sayName(); // Gred// 在另外一个对象的作用域中调用
const o new Object();
Person.call(o, Alice, 27, Nurse);
o.sayName(); // Alice 缺点每个方法都要在每个实例上重新创建一遍。 解决方法把函数转移到构造函数外。 function Person(name, age, job) {this.name name;this.age age;this.job job;this.sayName sayName
}
function sayName() {alert(this.name)};
const personOne new Person(lee, 29, Software Engineer)
const personTwo new Person(Gred, 24, Doctor) 如上两个实例的sayName共享了一个全局的sayName方法。解决了2个函数做同一件事的问题。但是新问题又来了 在全局作用域中定义的函数实际上只能被某个对象调用这让全局作用域有点名不副实 如果对象需要定义很多方法那么就要定义很多全局函数导致我们这个自定义的引用类型丝毫没有封装性可言。 3. 原型模式 1 针对以上构造函数的痛点原型模式可以解决这些问题。 我们创建的每个函数都有一个prototype原型属性这个属性是一个指针指向一个对象而这个对象的作用是包含可以由特定类型的所有实例共享的属性和方法。prototype就是通过调用构造函数而创建的那个对象实例的原型对象。使用原型对象的好处就是不用在构造函数中定义对象实例的信息而是可以将这些信息直接添加到原型对象中。 function Person() {}
Person.prototype.name lee;
Person.prototype.age 29;
Person.prototype.job Software Engineer;
Person.prototype.sayName function() {alert(this.name)
};
const personOne new Person();
personOne.sayName(); // lee
const personTwo new Person();
personTwo.sayName(); // lee
console.log(personOne.sayName personTwo.sayName); // true//简写
function Person(){}
Person.prototype {constructor: Person,name: lee,age: 29,job: Software Engineer,sayName: function(){alert(this.name)}
}; 2默认情况下所有原型对象都会自动获得一个constructor构造函数属性这个属性是一个指向prototype属性所在函数的指针。如上例子Person.prototype.constructor指向Person。 Person.prototype.constructor Person // true 3当调用构造函数创建一个新实例后该实例的内部将包含一个指针内部属性指向构造函数的原型对象。这个内部属性[ [ Prototype ] ]虽然无法访问到。但是可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系。如果[ [ Prototype ] ]指向调用isPrototypeOf()方法的对象Person.prototype,那么这个方法就返回true。 console.log(Person.prototype.isPrototypeOf(personOne)); // true
console.log(Person.prototype.isPrototypeOf(personTwo)); // true 4Object.getPrototypeOf() 这个方法返回[ [ Prototype ] ]的值 console.log(Object.getPrototypeOf(personOne) Person.prototype); // true
console.log(Object.getPrototypeOf(personOne).name); // lee
console.log(Object.getPrototypeOf(personTwo) Person.prototype); // true
console.log(Object.getPrototypeOf(personTwo).name); // lee 5使用delete可以删除实例中的属性 personOne.name Alice;
console.log(personOne.name) // Alice 来自实例
console.log(personTwo.name) // lee 来自原型
delete personOne.name;
console.log(personOne.name) // lee 来自原型 6hasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型中。如果该属性存在于实例中则返回true。 personOne.name Alice;
console.log(personOne.hasOwnProperty(name)) // true
console.log(personTwo.hasOwnProperty(name)) // false 7in操作符会在通过对象能够访问给定属性时返回true无论该属性存在于实例中还是原型中。 personOne.name Alice;
console.log(name in personOne) // true name在实例中
console.log(name in personTwo) // true name在原型中 8getOwnPropertyNames()方法得到所有实例属性无论它是否可枚举。 const keys Object.getOwnPropertyNames(Person.prototype);
console.log(keys); // [constructor,name,age,job,sayName] 9可以随时给原型添加属性和方法但是如果是重写整个原型对象就相当于把原型修改为另外一个对象就等于切断了构造函数与最初原型之间的联系。 function Person(){}
const friend new Person();
Person.prototype {name: lee,age: 29,job: Software Engineer,sayName: function(){alert(this.name)}
};
friend.sayName(); // error
//因为这时的friend指向的是以前的Person,而以前的是没有sayName方法的所以报错。
//而且这里旧的原型对象和新的原型对象的指针都指向Person缺点 1所有实例在默认情况下都将取得相同的属性值。上面例子中定义的name,age等2原型中存在引用类型会导致每一个实例共享这个引用类型。如下例子每一个实例中的friends会因为其中一个实例的修改都共享了这个修改后的结果。 function Person(){}
Person.prototype {constructor: Person,name: lee,age: 29,friends: [Jack, Bob],job: Software Engineer,sayName: function(){alert(this.name)}
};
const personOne new Person();
const personTwo new Person();
personOne.friends.push(Ivan);
console.log(personOne.friends); // [Jack, Bob, Ivan]
console.log(personTwo.friends); // [Jack, Bob, Ivan]
console.log(personOne.friends personTwo.friends); // true 4. 组合使用构造函数模式和原型模式 构造函数模式用于定义实例属性而原型模式用于定义方法和共享属性。每个实例都会有自己的一份实例属性的副本但同时又共享着对方法的引用最大限度地节省了内存。 function Person(name, age, job) {this.name name;this.age age;this.job job;this.friends [Jack, Bob];
}
Person.prototype {constructor: Person,sayName: function() {alert(this.name);}}
const personOne new Person(lee, 29, Software Engineer)
const personTwo new Person(Gred, 24, Doctor)
personOne.friends.push(Van);
console.log(personOne.friends); // [Jack, Bob, Ivan]
console.log(personTwo.friends); // [Jack, Bob]
console.log(personOne.friends personTwo.friends); // false
console.log(personOne.sayName personTwo.sayName); // true