javascript中的物件
1 建立物件
在js中建立物件非常的簡單
var obj={}
這樣,我們就建立了一個物件
2 物件的繼承
在ES6之前,javascript物件的繼承是通過原型(prototype)來實現的。在ES6之後的繼承方式類似於java
2.1 方式1 通過prototype建立物件
舉例
var student = { name: 'no_name', height: 1.2, run: function () { console.log(this.name + ' is running...'); } }; var xiaoming = { name:'小明' }; xiaoming.__proto__ = student;
訪問屬性和方法
xiaoming.name; // '小明' xiaoming.run(); // 小明 is running...
xiaoming
有自己的name
屬性,但並沒有定義run()
方法。不過,由於小明是從student
繼承而來,只要student
有run()
方法,xiaoming
也可以呼叫
需要注意的是,上述示例只用於演示,在平時開發過程中不要直接用obj.__proto__去改變一個物件的原型。
2.2 通過Object.create()建立物件
var xiaoming=Object.create(student) xiaoming.name='小明' //判斷原型是否是student xiaoming.__proto__===student // 返回true
2.3 通過建構函式建立物件
定義一個建構函式
function Student(name) { this.name = name; this.hello = function () { alert('Hello, ' + this.name + '!'); } }
咦,這不就是一個普通函式嗎。是的,這確實就是一個普通函式,但是如果我們通過如下方式使用,則這個普通函式就是一個建構函式
//通過建構函式建立一個新的物件 var xiaoming=newStudent('小明') //呼叫 xiaoming.name; // '小明' xiaoming.hello(); // Hello, 小明!
新建立的xiaoming
的原型鏈是:
xiaoming ----> Student.prototype ----> Object.prototype ----> null
3 原型鏈
當我們用obj.xxx
訪問一個物件的屬性時,JavaScript引擎先在當前物件上查詢該屬性,如果沒有找到,就到其原型物件上找,如果還沒有找到,就一直上溯到Object.prototype
物件,最後,如果還沒有找到,就只能返回undefined
。
例如
var arr = [1, 2, 3];
其原型鏈是
arr ----> Array.prototype ----> Object.prototype ----> null
再比如
function foo() { return 0; }
函式也是一個物件,它的原型鏈是:
foo ----> Function.prototype ----> Object.prototype ----> null
4 constructor屬性
用new Student()
建立的物件還從原型上獲得了一個constructor
屬性,它指向函式Student
本身
xiaoming.constructor === Student.prototype.constructor; // true Student.prototype.constructor === Student; // true Object.getPrototypeOf(xiaoming) === Student.prototype; // true xiaoming instanceof Student; // true
這是什麼亂七八糟的,看暈了,請看下圖
其中紅色箭頭是原型鏈,注意,
建構函式Student.prototype
指向的物件就是xiaoming
的原型物件,這個原型物件自己還有個屬性constructor
,指向Student構造
函式本身。
另外,建構函式Student
恰好有個屬性prototype
指向xiaoming
的原型物件,但是xiaoming
物件可沒有prototype
這個屬性,不過可以用__proto__
這個非標準用法來檢視。
不過還有個問題
xiaoming.name; // '小明' xiaohong.name; // '小紅' xiaoming.hello; // function: Student.hello() xiaohong.hello; // function: Student.hello() xiaoming.hello === xiaohong.hello; // false
xiaoming和xiaohong各自的name不同,這是對的
但是xiaoming和xiaohong各自擁有獨立的hello()方法,這就不合理了,這樣浪費了很多記憶體。解決方法是有的,就是通過上圖的原型鏈關係圖,我們如果把hello()方法移動到他們共同的原型上就可以了,如下圖
把hello()方法移動到上圖中的"某個物件"裡,而這個"某個物件"就是Student.prototype,因此我們把hello()方法移動到Student.prototype上。
修改程式碼如下
function Student(name) { this.name = name; } Student.prototype.hello = function () { alert('Hello, ' + this.name + '!'); };