菜單導航,《JS面向對象筆記一》, 參考書籍:阮一峰之《JavaScript標準參考教程》 一、構造函數和new命令 二、this關鍵字 三、構造函數和new命令 四、構造函數和new命令 五、構造函數和new命令 六、構造函數和new命令 七、構造函數和new命令 八、構造函數和new命令 一、構 ...
菜單導航,《JS面向對象筆記一》, 參考書籍:阮一峰之《JavaScript標準參考教程》
一、構造函數和new命令
1、構造函數
- JavaScript語言的對象體系,不是基於“類”的,而是基於構造函數(constructor)和原型鏈(prototype)
- 為了與普通函數區別,構造函數名字的第一個字母通常大寫,比如: var Person = function(){ this.name = '王大錘'; }
- 構造函數的特點:
a、函數體內部使用了this
關鍵字,代表了所要生成的對象實例;
b、生成對象的時候,必需用new
命令調用此構造函數
2、new
作用:就是執行構造函數,返回一個實例對象
var Person = function(name, age){ this.name = name; this.age = age; this.email = '[email protected]'; this.eat = function(){ console.log(this.name + ' is eating noodles'); } } var per = new Person('王大錘', 18); console.log(per.name + ', ' + per.age + ', ' + per.email); //王大錘, 18, [email protected] per.eat(); //王大錘 is eating noodles
執行new命令時的原理步驟:
- 創建一個空對象,作為將要返回的對象實例
- 將這個空對象的原型,指向構造函數的
prototype
屬性 - 將這個空對象賦值給函數內部的
this
關鍵字 - 開始執行構造函數內部的代碼
註意點:當構造函數裡面有return關鍵字時,如果返回的是非對象,new命令會忽略返回的信息,最後返回時構造之後的this對象;
如果return返回的是與this無關的新對象,則最後new命令會返回新對象,而不是this對象。示例代碼:
console.log('---- 返回字元串 start ----'); var Person = function(){ this.name = '王大錘'; return '羅小虎'; } var per = new Person(); for (var item in per){ console.log( item + ': ' + per[item] ); } //---- 返回字元串 start ---- //name: 王大錘 console.log('----- 返回對象 start ----'); var PersonTwo = function(){ this.name = '倚天劍'; return {nickname: '屠龍刀', price: 9999 }; } var per2 = new PersonTwo(); for (var item in per2){ console.log(item + ': ' + per2[item]); } //----- 返回對象 start ---- //nickname: 屠龍刀 //price: 9999View Code
如果調用構造函數的時候,忘記使用new關鍵字,則構造函數裡面的this為全局對象window,屬性也會變成全局屬性,
則被構造函數賦值的變數不再是一個對象,而是一個未定義的變數,js不允許給undefined添加屬性,所以調用undefined的屬性會報錯。
示例:
var Person = function(){ console.log( this == window ); //true this.price = 5188; } var per = Person(); console.log(price); //5188 console.log(per); //undefined console.log('......_-_'); //......_-_ console.log(per.price); //Uncaught TypeError: Cannot read property 'helloPrice' of undefinedView Code
為了規避忘記new關鍵字現象,有一種解決方式,就是在函數內部第一行加上 : 'use strict';
表示函數使用嚴格模式,函數內部的this不能指向全局對象window, 預設為undefined, 導致不加new調用會報錯
var Person = function(){ 'use strict'; console.log( this ); //undefined this.price = 5188; //Uncaught TypeError: Cannot set property 'helloPrice' of undefined } var per = Person();View Code
另外一種解決方式,就是在函數內部手動添加new命令:
var Person = function(){ //先判斷this是否為Person的實例對象,不是就new一個 if (!(this instanceof Person)){ return new Person(); } console.log( this ); //Person {} this.price = 5188; } var per = Person(); console.log(per.price); //5188View Code
二、this關鍵字
var Person = function(){ console.log('1111'); console.log(this); this.name = '王大錘'; this.age = 18; this.run = function(){ console.log('this is Person的實例對象嗎:' + (this instanceof Person) ); console.log(this); } } var per = new Person(); per.run(); /* 列印日誌: 1111 Person {} this is Person的實例對象嗎:true Person {name: "王大錘", age: 18, run: function} */ console.log('---------------'); var Employ = { email: '[email protected]', name: '趙日天', eat: function(){ console.log(this); } } console.log(Employ.email + ', ' + Employ.name); Employ.eat(); /* 列印日誌: --------------- [email protected], 趙日天 Object {email: "[email protected]", name: "趙日天", eat: function} */View Code
1、this總是返回一個對象,返回屬性或方法當前所在的對象, 如上示例代碼
2、對象的屬性可以賦值給另一個對象,即屬性所在的當前對象可變化,this的指向可變化
var A = { name: '王大錘', getInfo: function(){ return '姓名:' + this.name; } } var B = { name: '趙日天' }; B.getInfo = A.getInfo; console.log( B.getInfo() ); //姓名:趙日天 //A.getInfo屬性賦給B, 於是B.getInfo就表示getInfo方法所在的當前對象是B, 所以這時的this.name就指向B.nameView Code
3、由於this指向的可變化性,在層級比較多的函數中需要註意使用this。一般來說,在多層函數中需要使用this時,設置一個變數來固定this的值,然後在內層函數中這個變數。
示例1:多層中的this
//1、多層中的this (錯誤演示) var o = { f1: function(){ console.log(this); //這個this指的是o對象 var f2 = function(){ console.log(this); }(); //由於寫法是(function(){ })() 格式, 則f2中的this指的是頂層對象window } } o.f1(); /* 列印日誌: Object {f1: function} Window {stop: function, open: function, alert: function, confirm: function, prompt: function…} */ //2、上面代碼的另一種寫法(相同效果) var temp = function(){ console.log(this); } var o = { f1: function(){ console.log(this); //這個this指o對象 var f2 = temp(); //temp()中的this指向頂層對象window } } o.f1(); /* 列印日誌 Object {f1: function} Window {stop: function, open: function, alert: function, confirm: function, prompt: function…} */ //表示上面兩種寫法是一樣的效果,this的錯誤演示 //3、多層中this的正確使用:使用一個變數來固定this對象,然後在內層中調用該變數 var o = { f1: function(){ console.log(this); //o對象 var that = this; var f2 = function(){ console.log(that); //這個that指向o對象 }(); } } o.f1(); /* 列印日誌: Object {f1: function} Object {f1: function} */View Code
示例2: 數組遍歷中的this
//1、多層中數組遍歷中this的使用 (錯誤演示) var obj = { email: '大錘@sina.com', arr: ['aaa', 'bbb', '333'], fun: function(){ //第一個this指的是obj對象 this.arr.forEach(function(item){ //這個this指的是頂層對象window, 由於window沒有email變數,則為undefined console.log(this.email + ': ' + item); }); } } obj.fun(); /* 列印結果: undefined: aaa undefined: bbb undefined: 333 */ //2、多層中數組遍歷中this的使用 (正確演示,第一種寫法) var obj = { email: '大錘@sina.com', arr: ['aaa', 'bbb', '333'], fun: function(){ //第一個this指的是obj對象 var that = this; //將this用變數固定下來 this.arr.forEach(function(item){ //這個that指的是對象obj console.log(that.email + ': ' + item); }); } } obj.fun(); //調用 /* 列印日誌: 大錘@sina.com: aaa 大錘@sina.com: bbb 大錘@sina.com: 333 */ //3、多層中數組遍歷中this正確使用第二種寫法:將this作為forEach方法的第二個參數,固定迴圈中的運行環境 var obj = { email: '大錘@sina.com', arr: ['aaa', 'bbb', '333'], fun: function(){ //第一個this指的是obj對象 this.arr.forEach(function(item){ //這個this從來自參數this, 指向obj對象 console.log(this.email + ': ' + item); }, this); } } obj.fun(); //調用 /* 列印日誌: 大錘@sina.com: aaa 大錘@sina.com: bbb 大錘@sina.com: 333 */View Code
4、關於js提供的call、apply、bind方法對this的固定和切換的用法
1)、function.prototype.call(): 函數實例的call
方法,可以指定函數內部this
的指向(即函數執行時所在的作用域),然後在所指定的作用域中,調用該函數。
如果call(args)裡面的參數不傳,或者為null、undefined、window, 則預設傳入全局頂級對象window;
如果call裡面的參數傳入自定義對象obj, 則函數內部的this指向自定義對象obj, 在obj作用域中運行該函數
var obj = {}; var f = function(){ console.log(this); return this; } console.log('....start.....'); f(); f.call(); f.call(null); f.call(undefined); f.call(window); console.log('**** call方法的參數如果為空、null和undefined, 則預設傳入全局等級window;如果call方法傳入自定義對象obj,則函數f會在對象obj的作用域中運行 ****'); f.call(obj); console.log('.....end.....'); /* 列印日誌: ....start..... Window {stop: function, open: function, alert: function, confirm: function, prompt: function…} Window {stop: function, open: function, alert: function, confirm: function, prompt: function…} Window {stop: function, open: function, alert: function, confirm: function, prompt: function…} Window {stop: function, open: function, alert: function, confirm: function, prompt: function…} Window {stop: function, open: function, alert: function, confirm: function, prompt: function…} **** call方法的參數如果為空、null和undefined, 則預設傳入全局等級window;如果call方法傳入自定義對象obj,則函數f會在對象obj的作用域中運行 **** Object {} .....end..... */View Code
call可以接收多個參數:第一個參數是this所指向的那個對象,後面的參數就是函數調用時需要的參數,模擬簡寫為:
func.call(thisValue, arg1, arg2, ...); 示例:
var obj = { name: '張三', age: 10, email: '張三@sina.com' } function change(name, age){ this.name = name; this.age = age; console.log(this); } change.call(obj, '王大錘', '28'); //Object {name: "王大錘", age: "28", email: "張三@sina.com"}View Code