首頁 > web前端 > js教程 > 詳細介紹JavaScript的創建對象

詳細介紹JavaScript的創建對象

零下一度
發布: 2017-06-28 13:43:13
原創
1027 人瀏覽過

這篇文章主要為大家詳細介紹了JavaScript創建物件的相關資料,具有一定的參考價值,有興趣的小夥伴們可以參考一下

JavaScript對每個創建的物件都會設定一個原型,指向它的原型物件。

當我們用obj.xxx存取一個物件的屬性時,JavaScript引擎先在目前物件上尋找該屬性,如果找不到,就到其原型物件上找,如果還沒找到,就一直上溯到Object.prototype對象,最後,如果還沒找到,就只能回傳undefined。
例如,建立一個Array物件

var arr = [1, 2, 3];
登入後複製

其原型鍊是:

arr ----> Array.prototype --- -> Object.prototype ----> null

Array.prototype定義了indexOf()、shift()等方法,因此你可以在所有的Array物件上直接調用這些方法。
當我們建立一個函數時:

function foo() {
  return 0;
}
登入後複製

函數也是一個對象,它的原型鍊是:

foo ----> Function.prototype --- -> Object.prototype ----> null

由於Function.prototype定義了apply()等方法,因此,所有函數都可以呼叫apply()方法。

很容易想到,如果原型鏈很長,那麼存取物件的屬性就會因為花更多的時間查找而變得更慢,因此要注意不要把原型鏈搞得太長。

建構子

#除了直接用{ ... }建立一個物件外,JavaScript也可以用一種建構函數的方法來建立物件。它的用法是,先定義一個建構子:

function Student(name) {
  this.name = name;
  this.hello = function () {
    alert('Hello, ' + this.name + '!');
  }
}
登入後複製

你會問,咦,這不是一個普通函數嗎?

這確實是一個普通函數,但是在JavaScript中,可以用關鍵字new來呼叫這個函數,並傳回一個物件:

var xiaoming = new Student('小明');
xiaoming.name; // '小明'
xiaoming.hello(); // Hello, 小明!
登入後複製

注意,如果不寫new,這就是一個普通函數,它傳回undefined。但是,如果寫了new,它就變成了一個建構函數,它綁定的this指向新創建的對象,並默認返回this,也就是說,不需要在最後寫return this;。

新建立的xiaoming的原型鍊是:

xiaoming ----> Student.prototype ----> Object.prototype - ---> null

也就是說,xiaoming的原型指向函數Student的原型。如果你又創建了xiaohong、xiaojun,那麼這些物件的原型與xiaoming是一樣的:
xiaoming ↘
xiaohong -→ Student.prototype ----> Object.prototype ---- > null
xiaojun  ↗

用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、xiaohong的原型對象,這個原型物件自己還有個屬性constructor,指向Student函數本身。
另外,函數Student恰好有個屬性prototype指向xiaoming、xiaohong的原型對象,但是xiaoming、xiaohong這些對象可沒有prototype這個屬性,不過可以用proto這個非標準用法來查看。
現在我們就認為xiaoming、xiaohong這些物件「繼承」自Student。
不過還有一個小問題,注意觀察:

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是一個函數,但它們是兩個不同的函數,雖然函數名稱和程式碼都是相同的!
如果我們透過new Student()創建了很多對象,這些對象的hello函數實際上只需要共享同一個函數就可以了,這樣可以節省很多記憶體。

要讓創建的物件共享一個hello函數,根據物件的屬性查找原則,我們只要把hello函數移動到xiaoming、xiaohong這些物件共同的原型上就可以了,也就是Student. prototype:

修改程式碼如下:

function Student(name) {
  this.name = name;
}

Student.prototype.hello = function () {
  alert('Hello, ' + this.name + '!');
};
登入後複製

用new建立基於原型的JavaScript的物件就是這麼簡單!

忘記寫new怎麼辦

#

如果一个函数被定义为用于创建对象的构造函数,但是调用时忘记了写new怎么办?
在strict模式下,this.name = name将报错,因为this绑定为undefined,在非strict模式下,this.name = name不报错,因为this绑定为window,于是无意间创建了全局变量name,并且返回undefined,这个结果更糟糕。
所以,调用构造函数千万不要忘记写new。为了区分普通函数和构造函数,按照约定,构造函数首字母应当大写,而普通函数首字母应当小写,这样,一些语法检查工具如jslint将可以帮你检测到漏写的new。
最后,我们还可以编写一个createStudent()函数,在内部封装所有的new操作。一个常用的编程模式像这样:


function Student(props) {
  this.name = props.name || '匿名'; // 默认值为'匿名'
  this.grade = props.grade || 1; // 默认值为1
}

Student.prototype.hello = function () {
  alert('Hello, ' + this.name + '!');
};

function createStudent(props) {
  return new Student(props || {})
}
登入後複製

这个createStudent()函数有几个巨大的优点:一是不需要new来调用,二是参数非常灵活,可以不传,也可以这么传:


var xiaoming = createStudent({
  name: '小明'
});

xiaoming.grade; // 1
登入後複製

如果创建的对象有很多属性,我们只需要传递需要的某些属性,剩下的属性可以用默认值。由于参数是一个Object,我们无需记忆参数的顺序。如果恰好从JSON拿到了一个对象,就可以直接创建出xiaoming。

练习

请利用构造函数定义Cat,并让所有的Cat对象有一个name属性,并共享一个方法say(),返回字符串'Hello, xxx!':

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

以上是詳細介紹JavaScript的創建對象的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板