[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 = 0
}
// 為類添加 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'
}
let b = {
name: 'jack'
}
hello.call(a, 10, 40)
hello.apply(a, [10, 40] )
~~~
# 題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 。
# 題14、prototype 是干什么用的?
答:函數對象用來引用原型對象的(父對象)。
~~~
// 函數對象
function Abc() {
}
// 打印函數對象的原型對象(父對象)
console.log( Abc.prototype )
~~~
# 題15、JS 是如何實現繼承的?
答:通過原型鏈可以到父對象中找需要使用的屬性和方法,實現繼承。
# 題16、如何為對象動態的添加屬性和方法?
答:對象.xxx=xxx。
代碼演示:
~~~
let boy = {}
// 為對象添加屬性(變量)
boy.name = 'tom'
boy.age = 100
// 為對象添加方法(函數)
boy.hello = function() {
console.log(this.name)
}
boy.getAge = function() {
return this.age
}
~~~
# 題17、對象是如何創建的?
答:至少有兩種方法:
方法一、直接使用 {} 定義
~~~
let boy = {
name: 'tom',
age: 10
}
~~~
方法二、使用 new
~~~
let arr = new Array()
~~~
# 題18、如何從對象中動態的刪除一個屬性?
答:使用 delete 。
~~~
let boy = {}
// 為對象添加屬性(變量)
boy.name = 'tom'
boy.age = 100
// 刪除 age 屬性
delete boy.age
~~~