本文應該不會提到
- OOP
- class
本文會提到
- Javascript Object
- prototype, proto, [[prototype]], constructor
摘要
名詞:
- 屬性 properties, 屬性 attributes , 方法, 函式
- 物件導向, 類別, 原型
正文
物件
物件實字 object literal
{ }
建構式
function() {}
// Object initialiser or literal
{ [ nameValuePair1[, nameValuePair2[, ...nameValuePairN] ] ] }
// Called as a constructor
new Object([value])
建立物件
Object.create()
Object.create()
指定其原型物件與屬性,創建一個新物件。
語法 Object.create(proto[, propertiesObject])
var o;
// 建立以null為原型的物件
o = Object.create(null);
o = {};
// 等同於:
o = Object.create(Object.prototype);
範例
function heroCreator (name, act) {
const hero = {} //物件實字宣告方法
hero.name = name
hero.act = act
hero.attack = function () { console..log( `${this.name} 使用 ${this.act} 攻擊` ) }
return h
}
const pika = heroCreator('皮卡丘', '十萬伏特')
pika.attack()
現在想要改成共用方法 attack,不要直接寫進 creator
function heroCreator (name, act) {
const hero = {} //物件實字宣告方法
hero.name = name
hero.act = act
// hero.attack = function () { console..log( `${this.name} 使用 ${this.act} 攻擊` ) }
// 抽出來
return h
}
function attack (act) {
console..log( `${this.name} 使用 ${this.act} 攻擊`
}
const pika = heroCreator('皮卡丘', '十萬伏特')
pika.attack = attack
pika.attack()
const actions = {
atk: function () { console..log(${this.name} 使用攻擊`) }
def: function () { console..log(${this.name} 防禦`) }
}
function heroCreator(name) {
//const h = {}
const h = Object.create(actions)
h.name = name
h.act = act // act not defined
retrun h
}
用繼承的方式而不是直接寫進 creator,避免我忘記傳進 act
proto 所有的物件都有這個屬性
當在這個物件裡找不到某個屬性時,會去找物件的 proto 去尋找原型,一直到 null
const h1 = heroCreator('pika')
console.log(h1.__proto__) // 原型是 actions
JS 的標準內建物件
- Object
- Function
- Boolean
- Number
- String
- Array
- ...
- 所有的 Function 都有 prototype
- JS 有純值
1.__proto__
Uncaught SyntaxError: Invalid or unexpected token
let a = 1
a.__proto__
Number {0, constructor: ƒ, toExponential: ƒ, toFixed: ƒ, toPrecision: ƒ, …}
//自動 boxing 成 Number
.create vs .proto 指向
heroObj.create(actions)
等於
heroObj.__proto__ = actions
// 不要這樣做
this
誰呼叫,誰實 this
fun a () {
fun b() {}
b() //caller is global, this is window, 跟執行堆疊無關
}
fun heroFactory(name,act) {
this.name = name //this = global
}
fun heroFactory(name,act) {
var a = b = 2 // b=2 會被提升到 global 宣告一個 var b;
log(a) //2
lob(b) //2
}
log(a) //not defined
lob(b) //2 b 已經被拉到全域宣告
new 做了什麼?
改變 this 的指向
const h3 = new heroFactory('h3','run') // new 會幫忙做兩件事 1. this 指向 action 2. retrun this
const h4 = heroFactory('h4','fly') // retrun undefined
new hF() 裡
retrun 原始型別會被無視, return 複雜型別才可以
new
創出一個新的 object,我們叫它 O
把 O 的 proto 指向 "原型" 的 prototype,才能繼承原型鍊
拿 O 當作 context,呼叫 Person 這個建構函式
回傳 O
function 是物件
func a() {
log(this.age) //this == global this.name == undefined
}
a.age = 18
proto vs prototype
proto 是指向原型的 prototype 的一個屬性
fn.prototype 預設是空物件
物件原型
可以用不同方式 建構式 物件實字 定義
instance 的 proto 會指向他的原型,自定義的物件的 proto 會指向 function
Person.prototype:
instance 的屬性,所有的物件實例都會有這個屬性
proto 指向 prototype
============================
參考
- https://youtu.be/cwsH-L4zgTI
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/create
[教學] 深入淺出 JavaScript ES6 Class (類別)
- JavaScript | ES6 中最容易誤會的語法糖 Class - 基本用法
Javascripter 必須知道的繼承 prototype, [[prototype]], proto
JS基本觀念: 原型鏈(prototype chain)
該來理解 JavaScript 的原型鍊了
你懂 JavaScript 嗎?#19 原型(Prototype)
js中proto和prototype的区别和关系?
延伸
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript
[[Prototype]] javascript proto
javascript interview question "this"
jQuery source code
IFEE
contentful
not definded & undefined
hello()
Uncaught ReferenceError: hello is not defined
ReferenceError 沒有宣告過
let b = {} // 創造一個物件 b (用物件實字 or 建構式)
b.hello()
Uncaught TypeError: Cannot read property 'hello' is not a function
注意: 不是印出 undefuned ,而是 TypeError is not a function
如果改成 b.hello 就是 undefuned
undefined 怎麼出來的 => 原型鍊上找不到
b.protop 順著鍊上找到最後是 null,所以回傳 undefined
new
- 改變 this 的指向
hero = new Hero()
prototype vs proto
RECAP
fn.prototype 建構
fn.proto 指向原型