在構造函數內部經過this(用於指向當前對象)變量添加屬性或方法,
此處定義的屬性和方法都是爲對象自身所擁有,
每次經過類建立實例時, this指向的屬性都會獲得相應的建立.安全
var Person = function(name, sex) { // 私有屬性: 只能被【私有方法】和【特權方法】訪問 var contact = 'xxxxx@qq.com'; var number = '88888888'; // 私有方法: 在構造函數裏聲明, 能被【私有函數】【特權方法】訪問, 只能訪問【私有方法】和【私有屬性】 var getInfo = function(name, sex) { console.log('My name is ' + name + ', I’m a ' + sex + '!'); console.log('My email is ' + contact); }; // 公有屬性 this.name = name; this.sex = sex; // 特權方法: 能夠訪問【私有屬性】【私有方法】【公有屬性】 this.intro = function() { getInfo(name, sex); }; this.getContact = function(number) { console.log(number); }; // 構造器 this.getContact(number); };
經過點語法定義的屬性和方法不會添加到新建立的對象,所以類的實例沒法訪問, 只能經過類的自身(Person)訪問.閉包
// 類靜態公有屬性(對象不能訪) Person.isChinese = true; // 類靜態公有方法(對象不能訪問到) Person.speak = function() { console.log('what???'); };
一種是爲原型對象屬性賦值, 另外一種是將一個對象賦值給類的原型對象.
經過prototype繼承的屬性或方法是每一個對象經過prototype訪問到的,
因此每次經過類建立實例時, 這些屬性和方法不會再次建立.函數
Person.prototype = { // 顯示指定對象的constructor屬性 constructor: Person, // 公有屬性 hobby: 'reading', // 公有方法 sport: function() { console.log('run'); } }; // test: var tony = new Person('Tony', 'man', '25'); console.log('--- 訪問【公有屬性】 ---'); console.log(tony.name); // Tony console.log(tony.sex); // man console.log('--- 訪問【特權方法】 ---'); console.log(tony.intro()); // My name is Tony, I’m a man! // My email is xxxxx@qq.com console.log('--- 訪問【類靜態公有屬性】和【類靜態公有方法】 ---'); console.log(tony.isChinese); // undefined console.log(tony.speak()); // undefined console.log('--- 經過類自身訪問【類靜態公有屬性】和【類靜態公有方法】 ---'); console.log(Person.isChinese); // true console.log(Person.speak()); // what??? console.log('--- 訪問【公有屬性】及【公有方法】 ---'); console.log(tony.hobby); // reading console.log(tony.sport()); // run // 經過閉包實現: var Person = (function() { // 靜態私有變量 var isChinese = true; // 靜態私有方法 var speak = function() {}; // 建立類 var _person = function() { // 私有屬性: 只能被【私有方法】和【特權方法】訪問 var contact = 'xxxxx@qq.com'; var number = '88888888'; // 私有方法: 在構造函數裏聲明, 能被【私有函數】【特權方法】訪問, 只能訪問【私有方法】和【私有屬性】 var getInfo = function(name, sex) { console.log('My name is ' + name + ', I’m a ' + sex + '!'); console.log('My email is ' + contact); }; // 公有屬性 this.name = name; this.sex = sex; // 特權方法: 能夠訪問 this.intro = function() { getInfo(name, sex); }; this.getContact = function(number) { console.log(number); }; // 構造器 this.getContact(number); }; // 構建原型 _person.prototype = { constructor: _person, // 公有屬性 hobby: 'reading', // 公有方法 sport: function() { console.log('run'); } }; // 返回類 return _person; })();
標準原型寫法this
function Person() {} Person.prototype.sayHi = function() {} var me = new Person(); console.log(me.constructor === Person); // true;
對象字面量prototype
function Person() {} Person.prototype = { sayHi: function() {} } var me = new Person(); console.log(me.constructor === Person); // false; console.log(me.constructor === Object); // true;
使用對象字面形式改寫原型對象改變了構造函數的屬性,所以它如今指向Object而不是Person.code
由於原型對象具備一個constructor屬性,這是其餘對象實例所沒有的.
當一個函數被建立時,它的prototype屬性也被建立, 且該原型對象的constructor屬性指向該函數.
當使用對象字面形式改寫原型對象Person.prototype時, 其constructor屬性將被置爲泛用對象Object.對象
在改寫原型對象時手動重置其constructor屬性.繼承
// 對象字面量修正: function Person() {} Person.prototype = { constructor: Person, sayHi: function() { console.log('Hi~'); } } var me = new Person(); console.log(me.constructor === Person); // true; console.log(me.constructor === Object); // false;
var Person = function(name, sex) { this.name = name; this.sex = sex; }; var tony = new Person('Tony', 'boy'); console.log(tony.name); // Tony console.log(tony.sex); // boy var anna = Person('Anna', 'girl'); console.log(window.name); // Anna console.log(window.sex); // girl console.log(anna); // undefined console.log(anna.name); // Uncaught TypeError: Cannot read property 'name' of undefined
new能夠看做是對當前對象this不停地賦值,
若是沒有new, 則會直接執行函數, 由於函數在全局做用域中執行了,
因此在全局做用域中this指向的當前對象就天然是全局變量,
屬性都添加到window上面了;
另一個則由於Person類中沒有return語句,
則函數執行完沒有返回執行結果. 因此實例對象爲undefined;ip
// 建立對象的安全模式 var Person = function(name, sex) { // 判斷執行過程當中this是不是當前對象(若是是說明是用new建立的) if(this instanceof Person) { this.name = name; this.sex = sex; } else { // 不然從新建立這個對象 return new Person(name, sex); } }