一、內置一級構造函數Object(首字母大寫) 普通函數: 1)、不建議使用new關鍵字調用,否則就成為構造函數的調用了; 2)、可以用return語句返回值; 3)、函數內部不建議使用this關鍵字,函數裡面的this指向window,添加在this身上的屬性是全局屬性; 4)、函數命名以駝峰方式 ...
一、內置一級構造函數Object(首字母大寫)
1、普通函數和構造函數的特點
普通函數:
1)、不建議使用new關鍵字調用,否則就成為構造函數的調用了;
2)、可以用return語句返回值;
3)、函數內部不建議使用this關鍵字,函數裡面的this指向window,添加在this身上的屬性是全局屬性;
4)、函數命名以駝峰方式,首字母小寫;
構造函數:
1)、用new關鍵字調用,否則就成為普通函數的調用了;
2)、函數內部可以使用this關鍵字
在構造函數內部,this指向的是構造出的新對象。用this定義的變數或函數/方法,就是實例變數或實例函數/方法。需要用實例才能訪問到,不能用類型名訪問;
3)、預設不用return返回值(或者說有預設的返回值,也就是當前對象)
當然,我們也可以讓構造函數像普通函數一樣有返回值,但是返回值必須是引用類型對象,不能是值類型,如:null、undefined、boolean、number、string,否則這個返回值無效,依然返回構造的this對象。例如可以返回{a: 'A', b: 'B'}等等;
4)、函數命名建議首字母大寫,與普通函數區分開
不是命名規範中的,但是建議這麼寫。
5)、每個構造函數都有一個原型對象,原型對象包含一個指向構造函數的引用。
2、Object構造函數
Object instanceof Object // true Object instanceof Function // true typeof Object // 'function'
Object既是對象,也是函數,我們稱這種對象為函數對象,是js內置的構造函數。所有的函數對象都有一個預設屬性為prototype(原型),這個屬性Object.prototype是一個對象,所以稱為原型對象,它的屬性集合有:
console.log(Object.prototype);// 輸出如下: constructor:Object() __proto__: null hasOwnProperty __defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__ isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf get __proto__ set __proto__
特別重要的三個屬性:
1)、Object.prototype.constructor是指向當前內置函數對象的引用。如下:
Object.prototype.constructor === Object // true
2)、Object.prototype.__proto__存放的是繼承關係,Object是一級函數對象,它沒有繼承與別的對象,所以它繼承的是空對象null。如下:
Object.prototype.__proto__ === null // true
3)、hasOwnProperty判斷對象的屬性是否為原型中的屬性。
二、內置二級構造函數Function(首字母大寫)
Function instanceof Object // true Function instanceof Function // true typeof Function // 'function'
1、Function是內置構造函數對象,所以有一個預設屬性為prototype,這個屬性Function.prototype是一個對象,它的屬性集合分別有:
constructor:Function()
__proto__: Object.prototype
// 繼承Object的屬性(方法)
__defineGetter__
__defineSetter__
__lookupSetter__
Function.prototype.constructor是指向當前內置函數對象的引用,看:
Function.prototype.constructor === Function // true
js內置二級構造函數對象還有:
Date、Array、String、Boolean、RegExp、Number
用戶可以自定義的二級函數對象,如:
var Person = new Function(); // 也可以這樣(這隻是一種快捷方式): function Person() {} Person instanceof Object // true Person instanceof Function // true typeof Person // 'function'
還是那句話:所以的對象都是由函數創建的。
重點:
1、二級函數對象的原型對象都是繼承一級函數對象Object的原型對象,請看它們的原型指向:
Function.prototype.__proto__ === Object.prototype // true Date.prototype.__proto__ === Object.prototype // true Array.prototype.__proto__ === Object.prototype // true String.prototype.__proto__ === Object.prototype // true Boolean.prototype.__proto__ === Object.prototype // true RegExp.prototype.__proto__ === Object.prototype // true Number.prototype.__proto__ === Object.prototype // true Person.prototype.__proto__ === Object.prototype // true
什麼情況下產生繼承關係呢?個人覺得用new運算符 + 構造函數才會產生繼承關係,但是這些二級構造函數對象都是js內置的,他們和Object的繼承關係真是不清楚,可能是太菜了........
2、二級對象繼承了一級對象Object.prototype中的所以屬性,同時二級對象也有自己的私有屬性,是Object的原型中沒有的,我們經常用到的比如:
a). Date的私有屬性
getDate、getDay、getFullYear等等
b). String的私有屬性
length、slice、concat、search等等
c). Array的私有屬性
length、join、slice、splice等等
三、非函數對象(非內置函數對象的沒有內置的私有屬性)
1、常用的非函數對象,這種對象也稱為實例,這些對象都是new + 構造函數創建的,存在繼承關係
構造函數(函數對象),原型,實例之間的關係:每個構造函數都有一個原型對象,原型對象包含一個指向構造函數的引用,即constructor,而實例都包含一個指向原型對象的內部引用即proto。
1)、var obj = {};(new Object()) 2)、var arr = [];(new Array()) 3)、var Num = new Number(); 4)、var Str = new String();
2、非函數對象沒有原型,也就是沒有prototype屬性,但是非函數對象也是由函數創建的。既然它是由函數創建的,我們肯定能找到創建它的函數,如下:
a). json對象
var obj = new Object();// 很明顯可以看出有Object函數創建 obj.constructor === Object // true
b). 數組對象
var arr = new Array(); arr.constructor === Array // true
數組和對象還可以通過快捷方式創建,如:[]和{},實質上也是通過函數創建的,這種快捷方式叫做語法糖。請看:
var obj = {}; obj.constructor === Object // true var arr = []; arr.constructor === Array // true
總結:非函數對象都有constructor屬性指向創建該對象的函數。進一步說明對象都是由函數創建的。
3、非函數對象的繼承關係
1)、由2可以知道,非函數對象都是通過一級或者二級內置函數創建的,有contructor直接指向創建函數。那麼他們的繼承關係是怎樣的呢,是否有proto直接指向它繼承的對象?答案是當然有啦。在js中,只要你是一個對象,不是你繼承別的對象就是別的對象繼承你,我們叫這種通過原型對象繼承屬性的方式原型鏈。看:
a). json對象
var obj = {}; obj.__proto__ === Object.prototype // true Object.prototype.__proto__ === null // true // 這就是obj最長的原型鏈了 obj.__proto__.__proto__ === null // true
b). 數組對象
var arr = []; arr.__proto__ === Array.prototype // true Array.prototype.__proto__ === Object.prototype // true Object.prototype.__proto__ === null // true // 數組對象最長的原型鏈 arr.__proto__.__proto__.__proto__ === null // true
同理,其他非函數對象皆一樣。
2)、看一下非函數對象是否真的繼承了別的對象的屬性(方法)
a). 數組對象
var str = [1, 2, 3, 'a', 'b', 'c']; str.slice(2, 5); // [3, "a", "b"]
結果很明顯,我們經常用就不多舉例了。
4、非函數對象的內置對象arguments
arguments只出現在函數中,偽數組,格式和數組一樣:[1, 2, 3],用於接收函數的參數。由Object創建,如下:
function arg() { console.log(arguments instanceof Object); // true console.log(arguments.constructor === Object); // true console.log(arguments.__proto__ === Object.prototype); // true console.log(typeof arguments.slice); // undefined }
內置屬性length,可以通過索引訪問對應得值。它不是數組,不能用數組的方法。如:
arguments.slice(); // undefined
如何轉化為數組,從而可以使用數組的所以方法?
// Array.prototype.slice.call(arguments); function arg() { var arguments = Array.prototype.slice.call(arguments); console.log(arguments instanceof Object); // true console.log(arguments.constructor === Object); // false console.log(arguments.__proto__ === Object.prototype); // false console.log(typeof arguments.slice); // 'function' }
四、一級函數對象Object原型中的屬性hasOwnProperty
一級函數對象Object原型中的屬性hasOwnProperty會被所有的函數對象或者非函數對象繼承。
我們都知道對象是可以自定義屬性,如何判斷一個屬性是自定義的還是內置的或者繼承原型鏈中的呢?就看hasOwnProperty了本身了。
那麼我們哪些地方會用到hasOwnProperty。
1、判斷
var obj = { a: 'A', b: 'B' }; obj.hasOwnProperty('toString'); // false(繼承的) obj.hasOwnProperty('a'); // true (對象本身的)
2、遍歷
Object.prototype.newProperty = 'newPropertyValue'; var obj = { a: 'A', b: 'B' } for(var key in obj) { console.log(key + '==>' + obj[key]) } // 結果: // a==>A // b==>B // newProperty==>newPropertyValue 如何不遍歷newProperty呢? for(var key in obj) { if(obj.hasOwnProperty(key)) { console.log(key + '==>' + obj[key]) } }
// 結果: // a==>A // b==>B
五、總結
1、對象的定義:若幹屬性(方法)的集合;
2、所有的函數都是對象,但是對象不一定是函數,既是對象又是函數的對象稱為函數對象;
3、所有的函數對象都有一個預設屬性為prototype,這個屬性prototype是一個對象。其中有一個屬性為constructor,這個屬性是當前函數的引用;另外一個是__proto__屬性,指明繼承關係。
4、所有的非函數對象(實例)都有一個constructor屬性,這個屬性是一個存放著創建該對象的函數;同時也有__proto__屬性,指明繼承關係。
5、由第3、4點可以說明:所有的對象(函數對象和非函數對象)都是由函數創建的。
6、什麼是原型對象?
每一個函數對象都有的一個prototype屬性,這個屬性是一個對象,叫原型對象。只有函數(對象)才有原型,才能被繼承。
7、什麼是原型鏈(也叫原型對象鏈)?
用來繼承屬性(方法)的一條(原型)對象鏈。
(js任何一個對象不是被繼承就是繼承別的對象,所以js對象總能找到一條屬於它的用來繼承屬性(方法)的(原型)對象鏈。)
很多地方都參考了別的文章,但是都忘了出處,就不列舉了......,有錯歡迎指出!