構(gòu)造函數(shù)
function Persion(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
console.log(this.name);
}
}
var person1 = new Person('Joke',29,"Teacher");
var person2 = new Person('Greg',39,"Doctor");
上例中 person1,person2都是構(gòu)造函數(shù)Person的實(shí)例得院。
構(gòu)造函數(shù)其實(shí)與一般函數(shù)并沒有什么不同,不過一般默認(rèn)構(gòu)造函數(shù)的首字母大寫。它與一般函數(shù)的唯一區(qū)別就是通過new操作符來調(diào)用阴汇,其實(shí)任何函數(shù)只要通過new操作符來調(diào)用,那么他就可以作為構(gòu)造函數(shù)节槐。上面的Person可以通過下面任何一種方式調(diào)用
1.當(dāng)做構(gòu)造函數(shù)調(diào)用
var person1 = new Person('Joke',29,"Teacher");
2.作為普通函數(shù)調(diào)用
Person('Joke','30','Doctor');
window.sayName();
3.在另一個對象的作用域中調(diào)用
var o = new Object();
Persion.call(0,'Joke',29,"Teacher");
o.sayName();
構(gòu)造函數(shù)的問題
構(gòu)造函數(shù)模式雖然好用搀庶,但是也有問題。使用構(gòu)造函數(shù)的主要問題就是每個方法都要在每個實(shí)例上重新創(chuàng)建一遍铜异。在上面的例子中person1哥倔,person2都有sayName方法,但它們兩個的方法并不是同一個方法熙掺。這明顯是沒有必要的未斑。
function Persion(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;
}
function sayName(){
console.log(this.name);
}
這樣可以解決每個實(shí)例都有一個做相同事情的方法,但是又有了新的問題币绩,sayName是在全局定義的蜡秽,所以它可以在任何地方調(diào)用府阀,但我們的本意是要只是對象調(diào)用。
原型模式
我們創(chuàng)建的每一個函數(shù)都有一個prototype屬性芽突,這個屬性是一個指針试浙,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實(shí)例共享的屬性和方法寞蚌。如果按照字面意思來理解田巴,那么prototype就是通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建的對象實(shí)例的原型對象。原型的好處是可以讓所有實(shí)例共享它所包含的屬性和方法挟秤。
function Person() {}
Person.prototype.name = 'Nice';
Person.prototype.age = 20;
Person.prototype.job = 'Doctor';
Person.prototype.sayName = function() {
console.log(this.name)
}
// 也可以這樣寫
// Person.prototype = {
// name:'Nice',
// age:20,
// job:'Doctor',
// sayName:function(){
// console.log(this.name)
// }
// }
var p1 = new Person();
p1.sayName();
//p1.sayJob();//p1.sayJob is not a function
無論什么時候壹哺,只要創(chuàng)建了一個新函數(shù),就會根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個prototype 屬性艘刚,這個屬性指向函數(shù)的原型對象管宵。在默認(rèn)情況下,所有原型對象都會自動獲得一個constructor屬性攀甚,這個屬性包含一個指向prototype屬性所在函數(shù)的指針箩朴。就拿前面的例子來說。
console.log(Person.prototype.constructor) //? Person(){}
Person.prototype.sayJob = function() {
console.log(this.job);
}
var p2 = new Person();
p2.job = '老師';
p2.sayJob();
原型的問題
原型模式也不是沒有缺點(diǎn)秋度,首先炸庞,它身略了為構(gòu)造函數(shù)傳遞初始化參數(shù)的環(huán)節(jié),結(jié)果所有的實(shí)例默認(rèn)情況下都有相同的屬性值荚斯。但這不是最大的問題埠居,最大的問題還是共享的本質(zhì)導(dǎo)致的。原型中的所有屬性都是共享的鲸拥,這種共享對函數(shù)時非常適合的拐格,對于屬性也可以通過在實(shí)例中添加同名屬性覆蓋原型屬性。但是對于包含引用類型值的屬性來說刑赶,問題就比較突出了捏浊。
function Person() {}
Person.prototype = {
name: 'Nice',
age: 20,
job: 'Doctor',
friends:['張勝男','李時'],
sayName: function() {
console.log(this.name)
}
}
var p1 = new Person();
var p2 = new Person();
p1.friends.push('p1Friend');
// 由于js 引用類型的特質(zhì)
console.log(p2.friends)//["張勝男", "李時", "p1Friend"]
組合使用構(gòu)造函數(shù)和原型模式
//組合使用構(gòu)造函數(shù)和原型模式
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ['李三','王二'];
}
Person.prototype = {
constructor:Person,
sayName:function(){
console.log(this.name)
}
}
var p1 = new Person('流氓',20,'盲流');
var p2 = new Person('方子',23,'盲流');
p1.friends.push('p1的新朋友');
console.log(p1.friends)//["李三", "王二", "p1的新朋友"]
console.log(p2.friends)// ["李三", "王二"]