紅寶書第四版误墓,面對對象的重點,精華濃縮版,送給大家方篮,其中有部分是個人見解,歡迎指正
歡迎加我技術(shù)交流群 :811956471
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<title>對象_原型_繼承</title>
</head>
<body>
注解:person是構(gòu)造函數(shù)Person的實例對象励负。
1.hasOwnProperty():
-- 用于確定某個實例屬性或方法是在實例上還是在原型對象上,在實例上返回true藕溅,它會忽略那些從原型鏈上繼承的屬性;
-- 語法:object.hasOwnProperty('屬性名稱')继榆、如person.hasOwnProperty("name")巾表;
2.in 操作符:
-- 無論查找的屬性或方法是在原型上還是在實例上都返回true汁掠;
-- 語法 :屬性名 in 實例對象、如: "name" in person;
3.isPrototypeOf():
-- 檢測一個對象是否存在另一個對象的原型鏈上(判斷要檢查其原型鏈的對象是否存在于指定對象實例中集币,是返回true考阱,否返回fals);
-- 語法:object1.isPrototypeOf(Object2)鞠苟、如:Person.prototype.isPrototypeOf(person)乞榨;
4.instanceof
-- 檢測構(gòu)造函數(shù)的 prototype 屬性是否出現(xiàn)在某個實例對象的原型鏈上。
-- 語法:object instanceof constructor 当娱, object為某個實例對象吃既,constructor為某個構(gòu)造函數(shù)
</body>
<script type="text/javascript">
/*一、工廠模式:
1.1沒有解決對象標(biāo)識問題(即新創(chuàng)建的對象是什么類型)
*/
function createObj(name, age) {
let o = new Object();
o.name = name;
o.age = age;
return o
}
let getObj1 = createObj("Greg", 27);
let getObj2 = createObj("諸葛亮", 26);
console.log(getObj1 instanceof createObj) //false
console.log(getObj2 instanceof createObj) //false
/*二跨细、
2.1構(gòu)造函數(shù)模式:
無參可省去括號:let person1 = new Person()等同于let person2 = new Person;
a.優(yōu)勢:相比于工廠模式鹦倚、可以區(qū)分實例是來自哪個構(gòu)造函數(shù);
b.問題:其定義的方法會在每個實例上都創(chuàng)建一遍:下面person1 和 person2 都有名為 sayName()的方法扼鞋,
但這兩個方法不是同一個 Function 實例,因此,person1.sayName != person2.sayName
*/
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
console.log(this.name);
};
}
function Tree() {};
let person1 = new Person("Greg1", 27);
let person2 = new Person("Tom", 27);
let person3 = new Tree();
console.log(person1 instanceof Object); // true 申鱼,person1被認(rèn)為是Object實例,是因為所有自定義對象都繼承自O(shè)bject
console.log(person1 instanceof Person) //true
console.log(person2 instanceof Person) //true
console.log(person3 instanceof Person) //false
/*
2.2:解決構(gòu)造函數(shù) :
其定義的方法會在每個實例上都創(chuàng)建一遍問題 :
這樣雖然解決了相同邏輯的函數(shù)重復(fù)定義的問題云头,但全局作用域也因此被搞亂了捐友,因為那個函數(shù)實際上只能在一個對象上調(diào)用。如果這個對象需要多個方法,
那么就要在全局作用域中定義多個函數(shù)溃槐。這會導(dǎo)致自定義類型引用的代碼不能很好地聚集一起匣砖。這個新問題可以通過原型模式來解決。
*/
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = sayName
}
function sayName() {
console.log(99, this.name);
};
let personTest = new Person("Greg1", 27);
person66.personTest('諸葛', 20)
/* 三昏滴、
3.1原型模式
a.每個函數(shù)都會創(chuàng)建一個 prototype 屬性猴鲫,這個屬性是一個對象,包含應(yīng)該由特定引用類型的實例共享的屬性和方法谣殊。對象就是通過調(diào)用構(gòu)造函數(shù)創(chuàng)建的對象的原型
b.解決構(gòu)造函數(shù)存在的問題:使用這種原型模式定義的屬性和方法是由所有實例共享的,其定義的方法不會重復(fù)創(chuàng)建
c.原型存在的問題:無法傳遞初始化參數(shù)拂共,導(dǎo)致所有實例默認(rèn)都取得相同的屬性值,當(dāng)有引用值的屬性時姻几,其中一個實例修改原型上這個引用值時另外一個實例原型也會跟著改變
*/
function Person() {}
Person.prototype.name = '諸葛';
Person.prototype.sayName = function() {
console.log(this.name)
}
let person1 = new Person();
let person2 = new Person();
console.log(person1.sayName == person2.sayName); // true
/*
3.2原型模式--重寫原型:
a.可以看到宜狐、每次定義一個屬性或方法都會把 Person.prototype 重寫一遍
b.為了減少代碼冗余,因此:
*/
function Person() {}
Person.prototype = {
name: "Nicholas",
sayName() {
console.log(this.name);
}
};
// 這樣重寫之后,Person.prototype 的 constructor 屬性就不指向 Person蛇捌,而是指向了Object,解決這個問題抚恒,可以:
Person.prototype = {
name: "Nicholas",
constructor: Person,
sayName() {
console.log(this.name);
}
};
/*
3.3原型模式--重寫原型之原型的動態(tài)性:
未重寫原型之前,無論是先實例络拌,還是先給原型添加屬性和方法俭驮,實例都可以訪問到原型上的屬性方法
*/
let friend = new Person();
Person.prototype.sayHi = function() {
console.log("hi");
};
friend.sayHi(); // "hi",可以訪問到春贸,沒問題混萝!
/*
3.4原型模式--重寫原型之原型的動態(tài)性:
重寫原型之后遗遵,如果先實例,這個實例不能訪問到原型上的屬性方法譬圣,重寫整個原型會切斷最初原型與構(gòu)造函數(shù)的聯(lián)系
*/
let friend = new Person();
Person.prototype = {
constructor: Person,
name: "Nicholas",
};
friend.sayName(); // 錯誤瓮恭,無法訪問到
/* 四、繼承:
javascript的繼承是通過原型鏈實現(xiàn)
*/
/* 4.1厘熟、繼承之原型鏈:
a.原型鏈概念:利用原型讓一個引用類型繼承另一個引用類型的屬性和方法屯蹦。然后層層遞進(jìn),就構(gòu)成了實例與原型的鏈條绳姨,這就是所謂原型鏈登澜。
b.原型鏈存在問題:
--子類型在實例化時不能給父類型的構(gòu)造函數(shù)傳參;
--原型中包含引用值的時候,引用類型在實例中指向同一個地址飘庄,無法獨立
*/
function Parent() {
this.colors = ['red', 'green']
}
function Son() {}
Son.prototype = new Parent();
let son1 = new Son();
son1.colors.push('blue');
console.log(son1.colors) //["red", "green", "blue"]
let son2 = new Son();
console.log(son2.colors) //["red", "green", "blue"]
/* 4.2脑蠕、盜用構(gòu)造函數(shù):
-- 解決原型包含引用值導(dǎo)致的繼承問題
-- 缺點:須在構(gòu)造函數(shù)中定義方法、函數(shù)不能重用跪削、子類也不能訪問父類原型上定義的方法
*/
function Parent(name = '諸葛亮') {
this.name = name;
this.colors = ['red', 'green']
};
Parent.prototype.sayName = function() {
console.log(this.name)
};
function Son() {
Parent.call(this, '劉備')
}
let son1 = new Son();
son1.colors.push('blue');
console.log(son1.sayName()); //undefined
/* 4.3谴仙、組合繼承(偽經(jīng)典繼承):
-- 解決盜用構(gòu)造函數(shù)繼承問題
-- 組合繼承彌補了原型鏈和盜用構(gòu)造函數(shù)的不足,是 JavaScript 中使用最多的繼承模式碾盐。而且組合繼承也保留了 instanceof 操作符和 isPrototypeOf() 方法識別合成對象的能力
*/
function Parent(name = '諸葛亮') {
this.name = name;
this.colors = ['red', 'green']
};
Parent.prototype.sayName = function() {
console.log(this.name)
};
function Son(name) {
// 繼承屬性
Parent.call(this, name)
}
// 繼承方法
Son.prototype = new Parent();
let son1 = new Son('劉備');
son1.colors.push('blue');
console.log(son1.sayName()); //劉備
/* 4.4晃跺、原型式繼承:
-- 本質(zhì)是執(zhí)行了一次淺復(fù)制,和原型鏈存在問題的是一樣的毫玖,問題見:四掀虎、4.1
-- 下面是例子:可以看到,最后他們引用類似對象是同一個了付枫,引用對象繼承無法各自獨立
-- 自定義的object()方法等同于es5新增的Object.create() 方法
*/
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
let person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
let anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
let yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
console.log(person.friends); // "Shelby,Court,Van,Rob,Barbie"
/* 4.5烹玉、寄生式繼承:
-- 通過寄生式繼承給對象添加函數(shù)會導(dǎo)致函數(shù)難以重用,與構(gòu)造函數(shù)模式類似
*/
/* 4.6阐滩、寄生式組合繼承:
-- 寄生式組合繼承通過盜用構(gòu)造函數(shù)繼承屬性二打,但使用混合式原型鏈繼承方法,基本思路是不通過調(diào)用父類構(gòu)造函數(shù)給子類原型賦值掂榔,而是取得父類原型的一個副本
--子類原型最終包含超類對象的所有實例屬性址儒,子類構(gòu)造函數(shù)只要在執(zhí)行時重寫自己的原型就行了
*/
// 4、寄生組合式繼承
function inheritPrototype(subType, superType) {
var myprototype = Object(superType.prototype); //創(chuàng)建對象
myprototype.constructor = subType; //增強對象
subType.prototype = myprototype; //指定對象
}
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function() {
console.log(this.age);
};
let sub1 = new SubType('諸葛亮', 36)
console.log(sub1);
</script>
</html>