填坑-十萬個爲何?(4)

簡介:不少概念不清或忘記,從新構建本身的知識體系。天天問本身1~多個問題。我是菜鳥 成爲大神之路!html

1. JavaScript建立對象的方法?

①語法結構建立的對象使用{},[]數組

var o = {name: "Lis",sex:16};     | o 這個對象繼承了Object.prototype上面的全部屬性
                                  | 
var arr = ["yo", "whadup", "?"];  | 數組都繼承於 Array.prototype (Array.prototype 中包含 indexOf, forEach等方法)
                                  | 
function fun(){                   | 函數都繼承於Function.prototype (Function.prototype 中包含 call, bind等方法)
  return 2;                       |
}                                 | 
複製代碼

②構造器建立的對象使用new
在 JavaScript 中,構造器其實就是一個普通的函數。當使用 new 操做符 來做用這個函數時,它就能夠被稱爲構造方法(構造函數)bash

function Graph() {
  this.vertices = [];
  this.edges = [];
}

Graph.prototype = {
  addVertex: function(v){
    this.vertices.push(v);
  }
};

var obj = new Graph();
obj是生成的對象,他的自身屬性有'vertices''edges'.
在obj被實例化時,obj.[[Prototype]]指向了Graph.prototype.
複製代碼

Object.create 建立的對象>>link
ECMAScript 5中引入了一個新方法。新對象的原型就是調用 create方法時傳入的第一個參數。app

class 關鍵字建立的對象
ECMAScript6 引入了一套新的關鍵字用來實現 class。使用基於類語言的開發人員會對這些結構感到熟悉,但它們是不一樣的。JavaScript 仍然基於原型。這些新的關鍵字包括 class, constructor,static,extends 和 superide

"use strict";

class Polygon {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

class Square extends Polygon {
  constructor(sideLength) {
    super(sideLength, sideLength);
  }
  get area() {
    return this.height * this.width;
  }
  set sideLength(newLength) {
    this.height = newLength;
    this.width = newLength;
  }
}

var square = new Square(2);
複製代碼

2. JavaScript繼承的實現方法?

// 定義一個交通工具類
function Vehicle() {
  // 屬性
  this.name;
  this.number;
  // 實例方法
  this.funBase = function(){
    console.log("交通工具名稱:"+this.name+"||"+"可乘坐人數:"+this.number);
  }
}
// 原型方法
Vehicle.prototype.funRatio = function(ratio) {
  console.log(this.name + ':' + ratio);
};
複製代碼
①原型鏈繼承★★

核心: 將父類的實例做爲子類的原型函數

function Car(){
    this.getName = function(){
        console.log(this.name);
        return this.name;
    }
};
function Airplane(){
    this.getName = function(){
        console.log(this.name);
        return this.name;
    }
};

Car.prototype = new Vehicle();
Car.prototype.name = '汽車';
Car.prototype.number = '20人';

Airplane.prototype = new Vehicle();
Airplane.prototype.name = '飛機';
Airplane.prototype.number = '100人';

var car = new Car();
var airplane = new Airplane();
//測試
car.funBase();
car.funRatio("60%");
car.getName();
airplane.funBase();
airplane.funRatio("36%");
airplane.getName();
console.log(car instanceof Vehicle); // true
console.log(car instanceof Car); //true
複製代碼

執行結果: 工具

特色:
* 很是純粹的繼承關係,實例是子類的實例,也是父類的實例
* 父類新增原型方法/原型屬性,子類都能訪問到
* 簡單,易於實現
缺點:
* 要想爲子類新增屬性和方法,必需要在new Animal()這樣的語句以後執行,不能放到構造器中
* 沒法實現多繼承
* 來自原型對象的全部屬性被全部實例共享(來自原型對象的引用屬性是全部實例共享的)(詳細請看附錄代碼: 示例1)
* 建立子類實例時,沒法向父類構造函數傳參

'推薦指數:★★(三、4兩大體命缺陷)'
複製代碼
②構造繼承★★

核心:使用父類的構造函數來加強子類實例,等因而複製父類的實例屬性給子類(沒用到原型)性能

function Car(){
  Vehicle.call(this);
  this.name = '汽車';
  this.number = '20人';
  this.getName = function(){
        console.log(this.name);
        return this.name;
    }
}

// 測試
var car = new Car();
car.funBase();
car.funRatio("60%");//TypeError: car.funRatio is not a function[詳細瞭解]
car.getName();
console.log(car instanceof Vehicle); // false
console.log(car instanceof Car); //true
複製代碼

執行結果 測試

特色:
* 解決了1中,子類實例共享父類引用屬性的問題
* 建立子類實例時,能夠向父類傳遞參數
* 能夠實現多繼承(call多個父類對象)
缺點:
* 實例並非父類的實例,只是子類的實例
* 只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法
* 沒法實現函數複用,每一個子類都有父類實例函數的副本,影響性能

'推薦指數:★★(缺點3)'
複製代碼
③實例繼承★★

核心:爲父類實例添加新特性,做爲子類實例返回ui

function Car(){
  var vehicle = new Vehicle();
  vehicle.name = '汽車';
  vehicle.number = '20人';
  vehicle.getName = function(){
        console.log(vehicle.name);
        return vehicle.name;
    }
    return vehicle;
}

// 測試
var car = new Car();
car.funBase();
car.funRatio("60%");//TypeError: car.funRatio is not a function[詳細瞭解]
car.getName();
console.log(car instanceof Vehicle); // true
console.log(car instanceof Car); //false
複製代碼

執行結果:

特色:
* 不限制調用方式,無論是new 子類()仍是子類(),返回的對象具備相同的效果
缺點:
* 實例是父類的實例,不是子類的實例
* 不支持多繼承

'推薦指數:★★'
複製代碼
④拷貝繼承★

核心:逐一複製父類實例的屬性方法給子類實例

function Car(){
  var vehicle = new Vehicle();
  for(var p in vehicle){
    Car.prototype[p] = vehicle[p];
  }
  this.getName = function(){
        console.log(this.name);
        return this.name;
    }
}

// 測試
Car.prototype.name = '汽車';
Car.prototype.number = '20人';
var car = new Car();
car.funBase();
car.funRatio("60%");
car.getName();
console.log(car instanceof Vehicle); //false
console.log(car instanceof Car); //true
複製代碼

執行結果:

特色:
* 支持多繼承
缺點:
* 效率較低,內存佔用高(由於要拷貝父類的屬性)
* 沒法獲取父類不可枚舉的方法(不可枚舉方法,不能使用for in 訪問到)

'推薦指數:★(缺點1)'
複製代碼
⑤組合繼承★★★★

核心:經過調用父類構造,繼承父類的屬性並保留傳參的優勢,而後經過將父類實例做爲子類原型,實現函數複用

function Car(){
  Vehicle.call(this);
  this.name = '汽車';
  this.number = '20人';
  this.getName = function(){
        console.log(this.name);
        return this.name;
    }
}
Car.prototype = new Vehicle();
Car.prototype.constructor = Car;//組合繼承也是須要修復構造函數指向

// 測試
var car = new Car();
car.funBase();
car.funRatio("60%");
car.getName();
console.log(car instanceof Vehicle); // true
console.log(car instanceof Car); //true
複製代碼

執行結果:

特色:
* 彌補了方式2的缺陷,能夠繼承實例屬性/方法,也能夠繼承原型屬性/方法
* 既是子類的實例,也是父類的實例
* 不存在引用屬性共享問題
* 可傳參
* 函數可複用
缺點:
* 調用了兩次父類構造函數,生成了兩份實例(子類實例將子類原型上的那份屏蔽了)

'推薦指數:★★★★(僅僅多消耗了一點內存)'
複製代碼
⑥寄生組合繼承★★★★

核心:經過寄生方式,砍掉父類的實例屬性,這樣,在調用兩次父類的構造的時候,就不會初始化兩次實例方法/屬性,避免的組合繼承的缺點

function Car(){
  Vehicle.call(this);
  this.name = '汽車';
  this.number = '20人';
  this.getName = function(){
        console.log(this.name);
        return this.name;
    }
}
(function(){
  // 建立一個沒有實例方法的類
  var Super = function(){};
  //設置原型
  Super.prototype = Vehicle.prototype;
  //將實例做爲子類的原型
  Car.prototype = new Super();
  // 須要修復下構造函數
  Car.prototype.constructor = Car; 
})();

// 測試
var car = new Car();
car.funBase();
car.funRatio("60%");
car.getName();
console.log(car instanceof Vehicle); // true
console.log(car instanceof Car); //true
複製代碼

執行結果:

特色:
* 堪稱完美
缺點:
* 實現較爲複雜

'推薦指數:★★★★(實現複雜,扣掉一顆星)'
複製代碼

3. Function.prototype.call() 實現繼承時的原理?(相關apply()、bind()方法的使用)

①call()、apply()、bind() 都是用來重定義 this 這個對象的!
②參數:
* call的參數是直接放進去的,第二第三第n個參數全都用逗號分隔,直接放到後面  obj.myFun.call(db,'成都', ... ,'string' );
* apply的全部參數都必須放在一個數組裏面傳進去  obj.myFun.apply(db,['成都', ..., 'string' ]);
* 
③方法:
* apply:調用一個對象的一個方法,用另外一個對象替換當前對象。例如:B.apply(A, arguments);即A對象'應用'B對象的方法。
* call:調用一個對象的一個方法,用另外一個對象替換當前對象。例如:B.call(A, args1,args2);即A對象'調用'B對象的方法。
複製代碼

參考文章:
www.cnblogs.com/humin/p/455…
www.cnblogs.com/lengyuehuah…

相關文章
相關標籤/搜索