建構式函式跟一般的function不同,不需要return,一定要搭配 new 運算子才可以建立一個新的物件。
function Person(name, age, city) {
this.name = name;
this.age = age;
this.city = city;
}
我們在建構式函式裡面訂定物件要的 property (key, value),
再把 key值 放在參數上,讓要建立物件的引數可以對應key ,就可以把引數 放進key 的 value裡面,產出的物件就會直接都有key, value 了!
而這個新產生的物件是建構式函式的 實例(instance)。
那要怎麼建立一個建構式函式呢?
this
綁定要建立的property。this
所綁定的property。function Person(name) {
this.name = name
}
const jade = new Person("Jade");
console.log(jade);
// Person { name: 'Jade' }
console.log(jade.name);
// Jade
每個經由建構式函式建立的實例(instance)的前面都有來自哪個建構式函式的名稱
還可以藉由.constructor
來知道這個實例的建構式函式是誰
但是其實new出來的物件其實前面都會有建構式函式的名字
console.log(jade.constructor);
// [Function: Person]
console.log(jade.constructor === Person);
// true
如果一次要建立好幾個同樣property的物件的話,
就可以利用建構式函式去創造好幾個實例了!
function Person(name,age,school) {
this.name = name,
this.age = age,
this.school = school
}
const jade = new Person("Jade",20,"TNUA");
const ann = new Person("Ann",18,"NTUA");
const april = new Person("April",19,"NTU");
console.log(jade);
console.log(ann);
console.log(april);
// Person { name: 'Jade', age: 20, school: 'TNUA' }
// Person { name: 'Ann', age: 18, school: 'NTUA' }
// Person { name: 'April', age: 19, school: 'NTU' }
前面講到可以用建構式函式創建好幾個property一樣的實例,
但這些實例其實還可以使用建構式函式的原型喔。
sayHello()
:function Person(name,age,school) {
this.name = name,
this.age = age,
this.school = school
}
Person.prototype.sayHello = function(){
console.log(`Hello, my name is ${this.name}, and I am ${this.age} years old`);
}
const jade = new Person("Jade",20,"TNUA");
const ann = new Person("Ann",18,"NTUA");
const april = new Person("April",19,"NTU");
console.log(jade);
console.log(ann);
console.log(april);
// Person { name: 'Jade', age: 20, school: 'TNUA' }
// Person { name: 'Ann', age: 18, school: 'NTUA' }
// Person { name: 'April', age: 19, school: 'NTU' }
console.log(jade.sayHello());
console.log(ann.sayHello());
console.log(april.sayHello());
// Hello, my name is Jade, and I am 20 years old
// undefined
// Hello, my name is Ann, and I am 18 years old
// undefined
// Hello, my name is April, and I am 19 years old
// undefined
就算sayHello()
這些實例沒有,可是創造他們的建構式函式有這個prototype,他們就可以使用!
可以想像這些實例是Person 建構式函式的小孩,只要Person有的,實例就可以有。
只要你爸有錢,你就可以有錢(誤)
現在我們知道建構式函式跟prototype之後,來聊聊new運算子,到底為什麼這些實例可以使用建構式的prototype呢?
先來看看MDN上的解釋:
The new operator lets developers create an instance of a user-defined object type or of one of the built-in object types that has a constructor function.
創建的過程簡單來說大概是:
__proto__
指向建構式函式prototype,讓兩個連在一起。現在來模擬一下new到底做了什麼事:
把原本的var jade = new Person("jade", 20)
模擬成var jade = newPerson("jade", 20)
,
來把new Person()
變成一個function newPerson()
來看看。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.log = function () {
console.log(this.name + ", age:" + this.age);
};
// 假裝把new變成一個function表示
// 模擬:var jade = new Person("jade", 20);
var jade = newPerson("jade", 20);
function newPerson(name, age) {
let obj = {}; // 創造一個空物件
Person.call(obj, name, age); //綁定新實例的this給建構式函式。
obj.__proto__ = Person.prototype;// 新實例的__proto__指向建構式函式函式的prototype,讓兩個連在一起。
return obj;
}
console.log(jade);
// Person { name: 'jade', age: 20 }
2022/10/27 更新
Chirs 提供的寫法,結合Object.create()
function newFn (constructor, name, age) {
// 創造一個空物件,並把obj.__proto__ = constructor.prototype
const obj = Object.create(constructor.prototype)
// 綁定this給obj,帶入name, age
obj.constructor(name, age);
return obj
}
const jade = newFn(Person, 'jade', 18);
Speaking Javascript 的寫法:
會再多判斷是否是物件的條件。
p. 268
function newOperator(Constr, args) {
var thisValue = Object.create(Constr.prototype);
var result = Constr.apply(thisValue, args)
if(typeof result === 'object' && result !== null){
return result
}
return thisValue
}
__proto__
連結建構式函式的prototype之後會來介紹__proto__
,今天就這樣囉!
明天見!
參考資料:【新手大哉問】property、key、value、reference,到底是什麼啦?
[筆記] 談談 JavaScript 中的 function constructor 和關鍵字 new
胡立 JS201
這段 重新實作 new 的實作
function newPerson(name, age) {
// 創造一個空物件
let obj = {};
Person.call(obj, name, age); //綁定新實例的this給建構式函式。
obj.__proto__ = Person.prototype;// 新實例的__proto__指向建構式函式函式的prototype,讓兩個連在一起。
return obj;
}
應該可以這樣寫,再將 MDN 的步驟合在一起
function newFn (constructor, name, age) {
// 立即創造一個空物件,這個先叫做新實例(newInstance)
const obj = {};
// 綁定新實例的this給建構式函式。
obj.constructor = constructor;
// 執行建構式
obj.constructor(name, age);
// 再來就會把新實例的__proto__指向建構式函式prototype,讓兩個連在一起。
return Object.create(obj.prototype); // 這一步可以簡化成這樣
// 也可以寫這樣
// obj.__proto__ = Person.prototype;
// return obj;
}
newFn(Person, 'jade', 18);
以上,是我覺得的理解方式
function newFn (constructor, name, age) {
// 創造一個空物件,並把obj.__proto__ = constructor.prototype
const obj = Object.create(constructor.prototype)
// 綁定this給obj,帶入name, age
obj.constructor(name, age);
return obj
}
const jade = newFn(Person, 'jade', 18);
Speaking Javascript 的寫法:
p. 268
function newOperator(Constr, args) {
var thisValue = Object.create(Constr.prototype);
var result = Constr.apply(thisValue, args)
if(typeof result === 'object' && result !== null){
return result;
}
return thisValue;
}