目录
面向对象编程
以对象功能划分问题。
特性:封装性、继承性、多态性。
易维护、易复用、易扩展,性能比面向过程低。
思维特点:
1、抽取对象共用的属性和行为组织成一个类
2、对类进行实例化、获取类的对象
ES6中的类和对象
class关键字声明一个类。
类名首字母大写。
class 类名{
//类属性、类方法
}
创建实例
var obj=new 类名();
构造函数constructor
constructor()方法是类的构造函数,用于传递参数、返回实例化对象,通过new命令生成对象实例时自动调用该方法,如果没有显示定义,类内部会自动创建一个constructor()。
<script>
class Person{
constructor(uname){
this.name=uname;
}
sayHi(){
console.log('嗨'+this.name);
}
}
var xx=new Person('小明');
console.log(xx);
xx.sayHi();
</script>
类里的所有函数不需要写function,多个函数之间不需要添加逗号分隔。
类的继承
子类可以继承父类的一些属性和方法。
<script>
class Parent{}
class Son extends Parent{}
</script>
<script>
class Parent{
giveMoney(){
console.log('give money');
}
}
class Son extends Parent{}
var son=new Son();
son.giveMoney();
</script>
super关键字
用于访问和调用对象父类的函数,构造函数和普通函数
<script>
class Parent{
constructor(x,y){
this.x=x;
this.y=y;
}
sum(){
console.log(this.x+this.y);
}
}
class Son extends Parent{
constructor(x,y){
this.x=x;
this.y=y;
}
}
var son=new Son(1,2);
son.sum(); //报错,因为子类没有使用super,不能用父类的方法
// 子类修改成以下代码
class Son extends Parent{
constructor(x,y){
super(x,y); //调用父类的构造方法
this.x=x;
this.y=y; // this要放在super下面
}
sum(){
super.sum(); //调用父类的普通方法
}
}
</script>
ES6类没有变量提升,必须先定义类才能实例化对象,类里面的共有属性和方法一定要使用this
<script>
class Start{
constructor(){
this.btn=document.querySelector('button');
this.btn.onclick=this.sing;
}
sing(){
console.log('lalalala');
}
}
</script>
类的this指向
constructor里的this指向的是创建的实例化对象。
普通方法里的this指向的是调用方法的对象。
构造函数和原型
ES6
ECMAScript,2015年06月发布,大部分浏览器还是ES5,也支持ES6,但只实现了ES6部分功能和特性。
ES6前对象由构造函数来定义。
创建对象的三种方式:
1、对象字面量
2、new Object()
3、自定义构造函数
构造函数和原型
构造函数是一种特殊的函数,主要用来初始化对象,为对象成员变量赋初值,总是与new一起使用。
new 执行时做的四件事
1、在内存中申请空间,创建一个空对象
2、让this指向这个新对象
3、执行构造函数里的代码,给这个空对象添加属性和方法
4、返回这个新对象,所以构造函数中不需要return
成员
构造函数中可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数内部的this上添加,分为静态成员和实例成员。
静态成员:在构造函数上添加的成员,只能由构造函数本身访问。
实例成员:在构造函数内部创建的对象成员,只能由实例化对象访问。
<script>
function Star(name){
this.username=name; //username是实例成员,只能通过实例化对象访问
}
Star.sex='男'; //sex是静态成员,只能通过构造函数访问
var xx=new Star('小明');
console.log(xx.username);
console.log(Star.sex);
</script>
构造函数存在内存浪费的问题。
<script>
function Star(name){
this.username=name;
this.sing=function(){
console.log('lalala');
}
}
var xx=new Star('小明');
var yy=new Star('小红');
</script>
每个对象的方法都要占空间
构造函数原型prototype
构造函数通过原型分配的函数是所有对象共享的。
每一个构造函数都有一个prototype属性,指向另一个对象。这个prototype属性就是一个对象,这个对象的所有属性和方法,都被构造函数所拥有。
可以把那些不变的方法定义在prototype对象上,这样所有的对象都可以共享。
原型是一个对象,我们称prototype为原型对象
原型的作用:共享方法
<script>
class Person{}
Person.prototype.sing=function(){
console.log('lalalla');
}
var xx=new Person();
var yy=new Person();
xx.sing();
yy.sing();
<script>
一般把共有属性定义在构造函数里,共有方法定义在prototype里。
对象原型__proto__
对象会有一个属性__proto__,指向构造函数的prototype原型对象,之所以对象可以使用构造函数的prototype原型对象的属性和方法就是因为对象有__proto__属性。
对象原型__proto__和原型对象prototype是等价的
<script>
class Person{}
var p=new Person();
console.log(p.__proto__ === Person.prototype); //true
</script>
对象原型__proto__存在的意义:为对象的查找机制提供一个方向,实际开发中不能使用这个属性。
constructor构造函数
对象原型和构造函数原型对象都有一个属性:constructor属性,指回构造函数本身。
constructor主要用于记录对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
<script>
function Person(){}
var p=new Person();
console.log(p.__proto__.constructor===Person.prototype.constructor); //true
console.log(p.__proto__); //构造函数指向Person
console.log(Person.prototype); //构造函数指向Person
</script>
修改原型对象,会覆盖原来的原型对象
<script>
function Person(){}
Person.prototype={
sing:function(){
console.log('sing');
}
run:function(){
console.log('run');
}
}
var xx=new Person();
var yy=new Person();
console.log(xx.__proto__===Person.prototype); //true
console.log(p.__proto__); //只包含sing和run,没有构造函数
console.log(Person.prototype); //只包含sing和run,没有构造函数
</script>
修改原型对象,利用constructor重新指向原来的构造函数
<script>
function Person(){}
Person.prototype={
constructor:Person,
sing:function(){
console.log('sing');
}
run:function(){
console.log('run');
}
}
var xx=new Person();
var yy=new Person();
console.log(xx.__proto__===Person.prototype); //true
console.log(p.__proto__); //有构造函数,sing,run
console.log(Person.prototype); //有构造函数,sing,run
</script>
原型对象的应用:扩展内置对象
通过原型对象,对内置对象进行扩展自定义方法
数组和字符串内置对象不能给原型对象覆盖操作:Array.prototype={}
<script>
Array.prototype.sum=function(){
var sum=0;
for(var i=0;i<this.length;i++){
sum+=this[i];
}
return sum;
}
var arr=[1,2,3];
console.log(arr.sum());
</script>
构造函数、实例、原型对象之间的关系
原型链
构造函数有prototype属性,指向prototype对象,prototype对象有constructor属性,指回构造函数。
对象有__proto__属性,指向prototype对象,prototype对象有constructor属性,指回构造函数。
原型对象prototype也是对象,
对象有__proto__属性,指向Object prototype对象,Object prototype对象有constructor属性,指回Object 构造函数。
Object 构造函数有prototype属性,指向Object prototype对象,Object prototype对象有constructor属性,指回Object 构造函数。
Object 对象有__proto__属性,指向null。
JavaScript成员查找机制
1、访问一个对象的属性方法时先看这个对象自身有没有
2、对象自身没有,找他的原型,即__proto__指向的prototype原型对象
3、原型对象没有,找Object原型对象
4、一直找到null
继承
ES6之前没有extends关键字实现继承,通过构造函数+原型对象模拟实现继承,称为组合继承。
call()
调用这个函数,并且修改函数运行的this指向
fun.call(thisArg,arg1,arg2...)
// thisArg: 当前调用函数this的指向对象
// arg1,arg2传递的其他对象
<script>
function fn(){
console.log(this);
}
fn(); //window
// 调用函数,等于fun();
fn.call(); //window
var obj={
name: 'andy';
}
// 改变this指向
fn.call(obj); // obj{name:'andy'}
</script>
<script>
function fn(x,y){
console.log(this);
console.log(x+y);
}
var obj={
name: 'andy';
}
// 改变this指向,传其他参数
fn.call(obj,1,2); // obj{name:'andy'} 3
</script>
借用构造函数继承父类型属性
通过call()把父类型的this指向子类型的this,实现继承。
<script>
function Father(uname){
this.uname=uname;
}
function Son(uname){
Father.call(this,uname);
}
</script>
<script>
function Father(uname){
this.uname=uname;
}
function Son(uname){
Father.call(this,uname);
}
Son.prototype=new Father(); //子类原型对象指向父类的构造函数
Son.prototype.constructor=Son; //利用对象形式改变了原型对象要利用constructor指回原构造函数
// 添加子类的专有方法
Son.prototype.exam=function(){
console.log('exam');
}
</script>
ES6通过类实现面向对象
class 类名{}
类的本质还是一个函数
console.log(typeof 类名); //打印function
类有原型对象,也有constructor属性,也可以通过原型对象添加方法
console.log(类名.prototype);
语法糖:一种简便写法,es6的类的写法就是es5的简便写法。
ES5新增方法
数组方法
遍历方法:forEach(), map(), filter(), some(), every()
array.forEach(function(currentValue,index,arr))
//数组当前项的值,当前项索引,数组
<script>
var arr=[1,3,5];
arr.forEach(function(value,index,array){
console.log('每个元素值:'+value+',下标:'+index);
});
</script>
array.filter(function(currentVale,index,arr))
//数组当前项的值,当前项索引,数组
// filter()方法返回一个新数组,包含所有满足条件的元素,用于筛选
<script>
var arr=[1,3,5];
arr.filter(function(value,index){
return value>1;
});
</script>
array.some(function(currentValue,index,arr))
// 返回一个布尔值,查找是否存在满足条件的元素,找到一个就终止查找
<script>
var arr=[1,3,5];
var flag=arr.some(function(value){
return value>1;
});
console.log(flag);
</script>
字符串方法
str.trim()
// 删除字符串两端空白字符,返回一个新字符
<script>
var str1=' hi ';
var str2=str1.trim();
console.log(str2); //hi
</script>
对象方法
Object.defineProperty(obj,prop,descriptior)
// 目标对象,属性名字,属性特性
// 定义对象中新属性,或修改原有属性
descriptor以对象形式书写,内包含:
value::设置属性的值,默认undefined;
writeable:值能否重写,默认false;
enumerable:是否能被枚举,默认false;
configurable:能否被删除或修改特性,默认false;
<script>
var obj={
id:1,
name:'小明',
age:18
}
Object.defineProperty(obj,'num',{
value:100,
enumerable:true
})
console.log(Object.keys(obj)) //返回对象的所有属性名
delete obj.num; //删除对象属性
</script>