[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时使用,把对象公共的方法写到原型上
原型的主要用途:保存公共的方法,避免重复定义
![](http://ww1.sinaimg.cn/large/007WurYGgy1gf7flkhtw5j31200iedqu.jpg)
代码演示:
~~~
// 不好的例子:
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
![](http://ww1.sinaimg.cn/large/007WurYGgy1gf7g2y8uh1j30y00u6jxs.jpg)
# 题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、什么是继承?
答:继承:一个对象如果有父对象,那么父对象中的属性和方法也同样被子对象所拥有。
![](http://ww1.sinaimg.cn/large/007WurYGgy1gf8h196snyj30w60fyguy.jpg)
# 题13、OOP 的三大特性是什么?
答:封装、继承、多态。
封装:把功能代码封装成一个一个的类来使用。
继承:子类直接拥有(继承)父类中的属性和方法。
多态:父类中的同一个方法被不同的子类继承之后,表示出不同的形态。
![](http://ww1.sinaimg.cn/large/007WurYGgy1gf8h5iamjsj30ua0i4jzf.jpg)
# 题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
~~~