[TOC]
# 題1、面向對象編程的英文縮寫?
答:OOP (Object Oriented Programming,面向對象編程)。
# 題2、面向對象編程和面向過程編程有什么區別?
答:
面向過程編程(OOP):把功能封裝成一個個的函數,然后通過調用函數來實現功能。(以函數為主)
面向對象編程: 把功能封裝成類,然后通過類創建對象,通過對象來實現功能。(以對象為主)
# 題3、類和對象是什么關系?
答: 必須先有類才能創建出對象,對象是由類創建出來的,一個類可以創建多個對象。
舉個現實中的例子:比如蓋房子:類就是圖紙(房子長什么樣),對象就是蓋出來的房子(實體)。 一個圖紙可以創建出N個實際的房子。
類就是對象的圖紙,類中描述了對象長什么樣(屬性),有哪些功能(方法)
# 題4、 JS 中如何定義一個類?
答: 在 Js 中主要有兩種方法定義類:
ES5 之前的方法(傳統方法):使用 function
~~~
// 定義 People 類(類的構造函數)
function People() { }
~~~
ES6 中的新方法:使用 class
~~~
class People { }
~~~
# 題5、類里面都可以放什么東西?
答:屬性(變量)和方法(函數)。
如何定義語法:
ES5 之前的方法(傳統方法): 使用 function
~~~
// 定義 People 類(類的構造函數)
function People() {
? ?// 屬性
? ?this.name = ''
? ?this.age = 0
}
// 為類添加 hello 方法
People.prototype.hello = function() {
? ?console.log('hello')
}
~~~
ES6 中的新方法:使用 class
~~~
class People {
? ?// 屬性
? ?name = ''
? ?age = ''
? ?// 方法
? ?hello() {
? ? ? ?console.log('hello')
? }
}
~~~
# 題6、如何創建一個對象?
答: 使用 new 。
代碼演示:創建 People 類的對象
~~~
// 定義 People 類(類的構造函數)
function People() {
? ?// 屬性
? ?this.name = ''
? ?this.age = 18
}
// 為類添加 hello 方法
People.prototype.hello = function () {
? ?console.log('hello');
}
?
// 創建對象
let p1 = new People()
let p2 = new People()
let p3 = new People()
?
/// 調用對象中的方法
p1.hello() ?// 讓 p1 說 hello
p2.hello() ?// 讓 p2 說 hello
p3.hello() ?// 讓 p3 說 hello
~~~
# 題7、什么是原型鏈?干什么用的?
答:
1. 每個對象都有一個父對象,這個父對象就叫做這個對象的原型,父對象還有父對象就形成一個鏈,所以叫做原型鏈。
2. 原型鏈的特點:當我們使用一個對象的屬性和方法時,如果對象中沒有這個屬性和方法,那么就會到它的父對象中去找,如果還沒有就再找父對象中去找。
3. 基于這個特點的用途:主要再OOP時使用,把對象公共的方法寫到原型上
原型的主要用途:保存公共的方法,避免重復定義

代碼演示:
~~~
// 不好的例子:
function People() {
? ?this.name = ''
? ?// 方法直接定義在類中(不好!!),每new一個對象,這個對象體內就會有一個 hello 方法,
? ?this.hello = function() {
? ? ? ?console.log('hello')
? }
}
// 每個對象的體內都有一個完全相同的 hello 方法(不好!!!浪費內存!!)
let p1 = new People()
let p2 = new People()
let p2 = new People()
?
// 好的做法:把方法定義到原型上
function People() {
? ?this.name = ''
}
People.prototype.hello = function() {
? ?console.log('hello')
}
// 每個對象體內沒有 hello 方法,當使用hello 方法時,它們會到同一個原型上去(hello 在內存中定義了一次)
let p1 = new People()
let p2 = new People()
let p2 = new People()
~~~
# 題8、在原型鏈有 prototype 和 proto 兩個屬性是干什么用的?
答:JS 中通過 prototype 和 **proto** 才能夠實現原型鏈機制。 函數對象訪問原型對象:**prototype** 。 普通對象訪問原型對象:**proto** 。
~~~
// 函數對象
function Hello() {
}
// 訪問 Hello 的原型(函數對象)
console.log( ?Hello.prototype ? )
?
?
// 普通對象
let p1 = {name:'tom'}
// 訪問 p1 對象的原型(普通對象)
console.log( p1.__proto__ )
~~~
# 題9、原型鏈有終點嗎?
答: JS 中所有對象的最終的原型都是 Object 這個函數對象,再往上就是 null 。
總結:
1. Object 的原型是所有 JS 中對象的祖先原型
2. 原型鏈的終點是 null

# 題10、什么是構造函數?什么是析構函數?
答: 構造函數:創建對象時被調用的函數。
析構函數:對象被銷毀時被調用的函數。(Js 中沒有析構函數)
~~~
// ES5 (People 就是構造函數也是類)
function People() {
}
let p1 = new People() ?// People 函數在創建對象時執行
?
?
// ES6 新語法
class People {
? ?// construtor 是構造函數,在創建對象時會被調用
? ?construdtor() {
? }
}
~~~
# 題11、apply 和 call 的用途和區別?
答:用途: 改變 this 的指向。
區別: 傳參數的方式不同。
this的含義:
在普通函數中:this 代表調用這個函數時的對象。
在箭頭函數中:自己沒有 this,箭頭函數中的 this 是從上一級函數中繼承過來的 this (上一級的 this)。
**用途:**
代碼演示、apply 和 call 的用途 (改變函數中 this 的指向)
~~~
let people = {
? ?name: 'tom',
? ?hello: function () {
? ? ? ?console.log(this.name);
?
? }
}
people.hello() ?// tom , this 代表 people 這個對象
?
let boy = {
? ?name: 'jack'
}
people.hello.call(boy) // jack , 修改 people.hello 中的 this 指向 boy 對象
people.hello.apply(boy) // jack , 修改 people.hello 中的 this 指向 boy 對象
?
?
~~~
代碼演示2、
~~~
function hello() {
? ?console.log(this.name)
}
let a = {
? ?name: 'tom'
}
let b = {
? ?name: 'jack'
}
hello.call(a) ? // tom ,修改 hello 函數中的 this 指向 a 對象
hello.apply(b) ?// jack , 修改 hello 函數中的 this 指向 b 對象
?
~~~
**區別:**
當函數有參數時,call 和 apply 在傳參數時的形式不同。
代碼演示、
~~~
function hello(a, b) {
? ?console.log(this.name + '-' + a + b)
}
let a = {
? ?name: 'tom'
}
hello.call(a, 10, 40) ? // tom-1040
hello.apply(a, [10, 40]) ? ?// tom-1040
?
~~~
# 題12、什么是繼承?
答:繼承:一個對象如果有父對象,那么父對象中的屬性和方法也同樣被子對象所擁有。

# 題13、OOP 的三大特性是什么?
答:封裝、繼承、多態。
封裝:把功能代碼封裝成一個一個的類來使用。
繼承:子類直接擁有(繼承)父類中的屬性和方法。
多態:父類中的同一個方法被不同的子類繼承之后,表示出不同的形態。

# 題14、this 是干什么用的?
答:this 一般都會使用在函數中,代表調用這個函數時的對象。
this 在普通函數和箭頭函數中的含義不同:
普通函數中: this 代表調用這個函數時的對象。(this 綁定的對象是在 `調用函數` 時確定)
~~~
let people = {
? ?name: 'tom',
? ?hello: function() {
? ? ? ?console.log(this.name)
? }
}
let b = {
? ?name: 'jack'
}
people.hello.call(b) ?// this 代表 b
people.hello() ? ?// this 代表 people
?
~~~
箭頭函數: this 代表它外層函數中的 this 。(this 在定義箭頭函數時就已經確定)無法通過 call 和 apply 改變箭頭函數中的 this 。
# 題15、prototype 是干什么用的?
答:函數對象用來引用原型對象的(父對象)。
~~~
// 函數對象
function Abc() { }
// 打印函數對象的原型對象(父對象)
console.log(Abc.prototype)
?
~~~
# 題16、JS 是如何實現繼承的?
?
答:通過原型鏈可以到父類中找需要使用的屬性和方法,實現繼承。
# 題17、如何為對象動態的添加屬性和方法?
答:對象.xxx=xxx
代碼演示:
~~~
let boy = {}
// 為對象添加屬性(變量)
boy.name = 'tom'
boy.age = 100
// 為對象添加方法(函數)
boy.hello = function() {
? ?console.log(this.name)
}
boy.getAge = function() {
? ?return this.age
}
?
~~~
# 題18、對象是如何創建的?
答:
方法一、直接使用{}定義
~~~
let boy = {
? ?name: 'tom',
? ?age: 10
}
?
~~~
方法二、使用 new 關鍵字
~~~
let obj = new Objack()
?
~~~
# 題19、如何從對象中動態的刪除一個屬性?
答:使用 delete .
~~~
let boy = {}
// 為對象添加屬性(變量)
boy.name = 'tom'
boy.age = 18
?
// 刪除 age 屬性
delete boy.age
?
~~~