一、介绍
1.编程思想有三种:
面向过程编程POP:分析出问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以。
面向对象编程OOP:把事物分解成一个个对象,然后由对象分工与合作,每一个函数,一定会有一个原型,属性的选择性放在实例化的对象中,函数写在原型上
函数式编程FP:把现实世界 的事物和事物之间的联系抽象到程序里,用来描述数据之间的映射,相同的输入始终要得到相同的输出。
2.优点:
具有灵活性,代码可服用,容易维护和开发
3.面向对象的特性:
封装性(低耦合,高内聚),继承性(子类继承父类中的一些属性和方法),多态性(重载)
4.new Foo()返回一个对象,这个对象叫做函数的实例化。(实例化出来的对象与函数同名)
5.new函数,函数就变成了构造函数(函数首字母大写,会返回构造函数的同名对象,每次调用都会产生一个新对象)
6.面向对象的思维特点:
抽取对象共用的属性和方法封装成一个类
对类进行实例化,获取类的对象,每实例化一次就产生一个新的对象
7.对象:是一组无序的相关属性和方法的集合
属性:事物的特征,在对象中用属性来表示
方法:事物的行为,在对象中用方法来表示
8.构造函数:用来初始化新创建对象的函数,里面有一个属性是prototype,改属性指向了实例对象的原型对象
实例对象:通过new构造函数,会返回一个对象,这个就是实例对象,有一个__proto__属性指向了构造函数的prototype属性
原型对象:构造函数的prototype指向的就是原型对象
二、面向过程和面向对象对比
面向过程:
优点:性能比面向对象高,适合跟硬件联系紧密的东西,如单片机采用的就是面向过程
缺点:没有面向对象易维护,易复用,易扩展
面向对象:
优点:易维护,复用,扩展,由于面向对象有封装、继承、多态的特性,可以设计出低耦合的系统,使系统更加灵活,更加易于维护
缺点:性能低
三、构造函数
1.概念:当将这个函数进行new,这个函数就成构造函数,为了与普通函数区别,构造函数的名第一个字母大写。
2.特点:函数体内使用了this关键字,代表了所要生成的对象实例(this指向最近一层函数包裹并返回当前函数的调用对象)
生成对象,必须使用new关键字实例化
四、原型
1.每个函数产生都会伴随一个原型(prototype)产生,一个实例对象产生都会产生一个__proto__指针,指向了构造函数的prototype属性
2.给构造函数的prototype属性(对象)添加一个方法,这个方法就可以被构造函数的实例所共享
Student指构造函数
s1指实例的对象
Student.prototype.constructor===s1.constructor===Student
Student.prototype.__proto__===s1.__proto__.__proto__===Object.prototype
Object.prototype.constructor === Object
Student.prototype===s1.__proto__
s1.__proto__.__proto_.__proto__ === Object.prototype.__proto__ === null
Student.constructor === Object.constructor=== Function
Function.prototype === Student.__proto === Object.__proto__
Function.prototype.constructor === Function
Function.prototype.__proto === Object.prototype
3.总结
每创建一个函数,该函数就会自动带有一个 prototype 属性(原型对象)。该属性是个指针,指向了一个对象。
原型对象上默认有一个属性 constructor,该属性也是一个指针,指向其相关联的构造函数。
通过new构造函数产生的对象实例,都有一个内部属性__proto__,指向了prototype原型对象。
所以对象实例能够访问构造函数原型对象上的所有属性和方法。
通俗点说就是,实例通过内部指针__proto__可以访问到原型对象,原型对象通过constructor指针,又可以找到构造函数。
__proto__是每个对象都有的一个属性,而prototype是函数才会有的属性。
function PC(type,brand,price){
this.type = type;
this.brand = brand;
this.price = price;
}
PC.prototype.playSong = function(){
return "播放歌曲";
}
var pc = new PC('T460P',"联想",15999);
console.log(PC.prototype); //{playSong: ƒ, constructor: ƒ} 构造函数的原型对象
console.log(pc.__proto__); //{playSong: ƒ, constructor: ƒ} 指向了构造函数的原型对象
console.log(pc.__proto__.__proto__); //{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, …} 构造函数的prototype上的__proto__指向内置构造函数的Object的原型对象
console.log(pc.__proto__.__proto__.__proto__); //null 内置构造函数Object的原型对象中的__proto__指针指向为null
4.js继承机制:通过原型对象实现继承
原型对象的作用:定义所有实例对象共享的属性和方法
5.原型链:所有的对象都有自己的原型对象,对象的原型就是原型的原型,一层一层的查找,所有对象的原型最终都可以寻找到Object.prototype,所有对象都继承了Object.prototype的属性和方法
注:如果对象和它的原型,都定制了同名的属性,那么优先读取对象自身的属性
一但修改了构造函数的原型对象,为防止引用出现问题,同时也要修改原型对象的constructor属性
五、constructor属性
1.每个对象在创建时都会自动拥有一个构造函数属性constructor
2.constructor是通过继承关系继承下来的,当前实例的对象父类就是__proto__,里面就有constructor属性,它继承了原型对象,constructor指向了当前的构造函数
3.constructor属性表示原型对象和构造函数之间的关联关系
Student===s1.constructor
六、new命令的原理
1.新生成一个对象,作为将要返回的对象实例
2.将这个空的对象原型对象,指向了构造函数的prototype属性对象
3.将这个实例对象的值赋值给函数内部的this关键字(也就是this就是new完的实例对象)
4.执行构造函数体内的代码,返回新对象
function create() {
let obj = new Object()
let Con = [].shift.call(arguments)
obj.__proto__ = Con.prototype
let result = Con.apply(obj, argument)
return typeof result === 'object' ? result : obj
}
七、继承:
1.原型继承
(1)把父类的实例作为子类的原型
Son.prototype = new Father()
(2)父原型对象赋值子原型对象
Son.prototype = Father.prototype
2.实例继承/冒充继承(call、apply):只复制了属性,没有复制到原型里的东西
function Father(name,age){ }
function Son(name,age){ Father.call(this,name,age);}
function Son(name,age){ Father.apply(this,[name,age]);}
function Son(name,age){ Father.apply(this,arguments);}
//call的是一个个的参数列表;apply的是一个数组(arguments也可以)