日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

JS继承

發布時間:2024/8/26 综合教程 32 生活家
生活随笔 收集整理的這篇文章主要介紹了 JS继承 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 原型鏈繼承

它是下面這個形式的。

function F() {
  this.f_age = 8;
  this.f_name = 'father';
}
F.prototype.getFAge = function() {
  return this.f_age;
}
function S() {
  this.s_age = 3;
}
S.prototype = new F();
S.prototype.getSAge = function() {
  return this.s_age;
}
let s = new S();
console.log(s.getFAge()); // 8
console.log(s.getSAge()); // 3
console.log(s.constructor);  // [Function: F]
console.log(s instanceof S); // true
console.log(s instanceof F); // true

它的主要過程:

實例化父類 F -> f
將子類的原型對象 S.prototype 指向 f
實例化子類 S -> s

加深理解:
s.__proto__ -> S.prototype -> f.__proto__ -> F.prototype

需要注意的是:

本來 S 的 constructor 是 S,但是因為 S.prototype 重寫了,所以現在 constructor 是 F.
查找機制: s -> S.prototype -> F實例 -> F.prototype

function F() {
  this.name = 'F';
}
F.prototype.name = 'F-prototype';
function S() {}
S.prototype = new F();
let s = new S();
console.log(s.name); // F

原型繼承中 子類 重寫 父類的方法

function F() {
  this.x = true;
}
F.prototype.getF = function() {
  return this.x;
}
function S() {
  this.y = false;
}
S.prototype = new F();
S.prototype.getS = function() {
  return this.y;
}
// 重寫父類型中的 getF
S.prototype.getF = function() {
  return '33';
}
let s = new S();
console.log(s.getS()); // false 
console.log(s.getF()); // 33,   原來的 父類中 返回 true
delete(S.prototype.getF);
console.log(s.getF()); // true
如果你想要改變(覆蓋)父類的方法,必須在子類的 原型對象 被 父類的實例 賦值之后 覆蓋。后來居上,你懂的。
后來居上的 字面量方法 也一樣,如下
function F() {}
function S() {}
S.prototype = new F();
// 下面的這句話重寫了上面這句話。
S.prototype = {
  getX: function() {
    return '33';
  }
}

原型鏈繼承的特點和示例代碼:

a. 原來的父類實例屬性 變為了 子類的原型屬性。共享性。(也可以是缺點)

function F() {
  this.colors = ['red', 'blue'];
}
function S() {}
S.prototype = new F();
let s1 = new S();
let s2 = new S();
s1.colors.push('yellow');
console.log(s1.colors); // ['red', 'blue', 'yellow']
console.log(s2.colors); // ['red', 'blue', 'yellow'] 

b. 創建子類型的實例的時候,不能像超類型的構造函數傳遞參數。(是不足之處)


2. 借用構造函數 繼承

真是騷操作啊。

原理:

A.誰調用了函數,函數中的 this 就指向誰。
B.利用 apply 和 call 在 子類 內部調用 函數。

function F() {
  this.colors = ['red', 'blue'];
}
function S() {
  F.call(this);
}
let s1 = new S();
let s2 = new S();
s1.colors.push('yellow');
console.log(s1.colors);  // ['red', 'blue', 'yellow']
console.log(s2.colors);  // ['red', 'blue']

特點:

屬性不會共享。(上面說了)
可以傳參

function F(name) {
  this.name = name;
  this.colors = ['red', 'blue'];
}
function S(name) {
  F.call(this, name);
}
let s1 = new S('ccc');

缺點在于函數復用。

其實和 JS構造模式 是一個道理。在原型鏈 中的 共享的函數還是很有必要的。一些屬性也是應該共享的。


3. 組合繼承: 跟JS模式中的 組合構造模式 很像。

可以傳參。
可以 選擇 是否共享屬性和方法。(非戰爭的年代,人們有權選擇過自己的生活)

function F(name) {
  this.name = name;
  this.colors = ['red'];
}
F.prototype.getF = function() {
  console.log(this.name);
}
function S(name, age) {
  F.call(this, name);
  this.age = age;
}
S.prototype = new F();
S.prototype.constructor = S;
S.prototype.getS = function() {
  console.log(this.age);
}
// 強行讓 constructor 為子類,缺點是 constructor 變為可枚舉。
let s1 = new S('s1', 18);
let s2 = new S('s2', 20);
s1.colors.push('yellow');
console.log(s1);    // S {name: 's1', colors: ['red', 'yellow'], age: 18}
console.log(s2);    // S {name: 's2', colors: ['red'], age: 20}
delete(s1.colors);      // 刪掉了 子類實例中,借用父類構造函數繼承的 colors
console.log(s1.colors); // 子類實例中:父類原型中的 colors 還是存在的。
// ---------------------------------------------------------------
console.log(s1.constructor); // [Function: S]
console.log(Object.keys(S.prototype)); // 其中包含 constructor 屬性

4. 原型式繼承: 可以說是 ES3中對 ES5中 Object.create 的實現了。

缺點很明顯:共享屬性。

function Create(o) {
  function F(){};
  F.prototype = o;
  return new F();
}
let person = {
  name: '123',
  colors: ['red']
}
let f1 = Create(person);
let f2 = Create(person);
f1.colors.push('yellow');
console.log(f2.colors);   // ['red', 'yellow']
ES5中的 Object.create(用作新對象原型的對象,可選的定義額外屬性的對象)

若是沒有第二個參數,和我們上方自己寫的 Create 方法相同。

let person = {
  name: '123',
  colors: ['red']
}
let f1 = Object.create(person);
let f2 = Object.create(person);
f1.colors.push('yellow');
console.log(f2.colors);   // ['red', 'yellow']

若是寫了第二個參數,則會覆蓋掉原型中的 屬性。

let person = {
  name: '123',
  colors: ['red']
}
let f1 = Object.create(person, {
  colors: {
    value: ['red']
  }
});
let f2 = Object.create(person, {
  colors: {
    value: ['red']
  }
});
f1.colors.push('yellow');
console.log(f2.colors);   // ['red']

在沒有必要興師動眾地 創建構造函數,只是想讓 一個對象 與 另外一個對象保持 相似的情況下,使用 原型式繼承 就可以了。


5. 寄生組合式繼承。

產生的原因是組合繼承 的缺點:

調用兩次父類。

1.創建子類原型的時候
2.子類型構造函數內部的調用

最后造成的結果。子類會包含 父類的全部 實例屬性。并且在調用子類構造函數的時候會重寫(覆蓋)一些屬性。

function Create(o) {
  function F() {};
  F.prototype = o;
  return new F();
}
// 1. 這一步為了 子類繼承 父類的原型
function Inherit(subType, superType) {
  let prototype = Create(superType.prototype);
  // 只承包了 父類的原型。
  prototype.constructor = subType;
  // 增強對象,重寫 被重寫的 constructor
  subType.prototype = prototype;
}

function F(name) {
  this.name = name;
  this.colors = ['blue'];
}
F.prototype.say = function() {
  console.log(this.name);
}
// 2. 這一步為了 子類繼承 父類的一些構造函數內部的東西
function S(name, age) {
  F.call(this, name);
  this.age = age;
}
Inherit(S, F);

疑問:其實本質上沒有啥差別。主要的騷操作就要在于:子類的原型繼承的地方改了下。


complete.

總結

以上是生活随笔為你收集整理的JS继承的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。