繼承
繼承目前有八種以上的方式實現(xiàn):原型鏈繼承、構(gòu)造函數(shù)繼承、組合繼承、寄生式、組合寄生式繼承、ES6類繼承extends等等。
組合寄生式繼承:最成熟和完美的繼承方式,解決了組合式兩次調(diào)用父類的構(gòu)造函數(shù)造成浪費的缺點。組合式繼承還有個問題,子類不是父類的實例,而子類的原型是父類的實例。寄生式繼承依托于原型繼承,寄生就像蟲子一樣,依托于某個對象,在其內(nèi)部生長(添加新方法和屬性),它是對原型繼承的第二次封裝。
思路:我們通過原型繼承拿到父類的副本,但還不能直接賦值給子類,因為父類原型對象復制得到的副本中constructor指向不是子類對象,所以在寄生式繼承中對這個副本做一次增強,修復其constructor屬性指向不明確的問題,最后得到的副本賦值給子類的原型。
核心代碼
function inheritPrototype(subType, superType){
// 創(chuàng)建對象,創(chuàng)建父類原型的一個副本
var prototype = Object.create(superType.prototype);
// 增強對象,彌補因重寫子類原型而失去的默認的constructor屬性
prototype.constructor = subType;
// 指定對象,將新創(chuàng)建的對象賦值給子類的原型
subType.prototype = prototype;
}
繼承實例
// 父類初始化實例屬性和原型屬性
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
// 定義子類,借用構(gòu)造函數(shù)傳遞增強子類實例屬性(支持傳參和避免篡改)
function SubType(name, age){
//構(gòu)造函數(shù)式繼承
SuperType.call(this, name);
//子類新增屬性
this.age = age;
}
// 將父類原型指向子類
inheritPrototype(SubType, SuperType);
// 新增子類原型方法
SubType.prototype.sayAge = function(){
alert(this.age);
}
//測試
var instance1 = new SubType("xyc", 23);
var instance2 = new SubType("lxy", 23);
instance1.colors.push("2"); // ["red", "blue", "green", "2"]
instance1.colors.push("3"); // ["red", "blue", "green", "3"]
拷貝
參考文章: js 深拷貝vs淺拷貝
數(shù)據(jù)類型的賦值
- 基本類型
- 基本數(shù)據(jù)類型存放在棧中(系統(tǒng)自動分配和釋放內(nèi)存)
- 基本數(shù)據(jù)類型的值不可改變,動態(tài)改變返回的是一個新的變量
- 基本類型的比較,是值的比較
- 引用類型
- 引用類型存放在堆中(內(nèi)存不會自動釋放),變量實際上是一個指向存放在棧內(nèi)存的指針
- 引用類型的值可以改變
- 引用類型比較是引用的比較(指針指向相同)
賦值和拷貝的區(qū)別
深拷貝:將 B 對象拷貝到 A 對象中,包括 B 里面的子對象,
淺拷貝:將 B 對象拷貝到 A 對象中,但不包括 B 里面的子對象
賦值和拷貝對比
淺拷貝核心代碼
function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}
深拷貝核心代碼
乞丐版
《你不知道的JavaScript(上)》中提及:
對于JSON安全(也就是可以被序列化為一個JSON字符串并且可以根據(jù)這個字符串解析出一個結(jié)構(gòu)和值完全一樣的對象)的對象來說,有一種巧妙的復制方法,代碼如下:
var newObj = JSON.parse(JSON.stringify(someObj));
這種方法要保證對象是JSON安全的,所以只適用于部分情況。
完美版
思路:遇到簡單類型,直接復制return;遇到復雜類型,賦值簡單類型,遞歸遍歷子復雜類型。
function deepCopy(obj){
//判斷是否是簡單數(shù)據(jù)類型
if(typeof obj == 'object'){
//復雜數(shù)據(jù)類型
var result = obj.constructor == Array ? [] : {};
for(let i in obj){
//若是對象,就是result[屬性名];若是數(shù)組,就是result[下標]
result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i];
}
}
else{
//簡單數(shù)據(jù)類型
var result = obj;
}
return result;
}
instanceOf
思路是順著原型鏈一直找,直到null
function instanceOf(left,right){
let proto = left.__proto__;
let prototype = right.prototype;
while(true) {
if(proto === null) return false
if(proto === prototype) return true
proto = proto.__proto__;
}
}