面向对象编程(一)

173 阅读4分钟

面向对象编程(oop):具有灵活,代码可复用性,高度模块化等特点

对象是什么

对象是单个实物的抽象,对象是一个容器,封装了对应的属性和方法。属性是对象的状态,方法是对象的行为。

构造函数

用来初始化新创建对象的函数

生成对象

需要一个模板(表示一类实物的共同特征),让对象生成。类就是对象的模板,但js不是基于类的,而是基于构造函数(constructor)和原型链(prototype)的。

//Dog是构造函数,为了区别于普通函数,首字母大写
function Dog(name,age){
    //name和age就是当前实例化对象的属性
    this.name = name;
    this.age = age;
}
var huahua = new Dog('huahua',3);

构造函数的特点

  1. 函数体内使用this,代表了所要生成的对象实例。
  2. 生成对象,必须使用new关键字实例化这个对象。

instanceof

校验实例

//语法: A instanceof B
//判断A是否是B的实例

function Dog(name){
	if(!(this instanceof Dog )){
        //this指向了window,外部没有使用new关键字
	    return new Dog(name);
    }else{
        //this指向了当前的实例,外部使用了new关键字
        this.name = name;
    }
}
var huahua=Dog('huahua');
console.log(huahua);

new命令内部原理

step1:创建一个空对象,作为将要返回的对象实例。

step2:将这个空的对象的原型对象,指向了构造函数的prototype属性对象p1.__proto__===Person.prototype

step3: 将这个实例对象的值赋值给函数内部的this

step4:执行构造函数内部的代码

function Person(name){
    this.name = name;
    //p.name = name;
}
var p1 = new Person('mjj');

constructor属性

每个对象在创建时都会自动拥有一个构造函数属性constructor

constructor属性继承自原型对象,指向了构造函数的引用Person(p1.constructor ===Person)

原型对象

//原型对象:Foo.prototype
//构造函数:用来初始化新创建对象的函数,Foo就是构造函数,他有一个属性prototype(f1给的),指向了实例对象f1的原型对象(__proto__)
function Foo(){};
//实例对象:f1就是实例对象,会自动给构造函数Foo赋予一个prototype属性,每一个实例对象中都有一个__proto__,指向构造函数Foo的原型。每个实例对象中都有一个constructor属性,这个constructor通过继承关系继承而来,他指向了当前的构造函数Foo
var f1 = new Foo();

原型对象、实例对象、构造函数之间的关系

function Foo(){};
var f1 = new Foo();

prototype的作用

js继承机制:通过原型对象实现继承,prototype的作用,就是定义了所有实例对象共享的属性和方法。

function Foo(){};
Foo.prototype.name = 'john';
var f1 = new Foo();
var f2 = new Foo();
console.log(f1.name);//john
console.log(f2.name);//john

原型链挖掘

js规定所有的对象都有自己的原型对象

原型链:对象的原型=>原型的原型=>原型的原型的原型....=>null

根据原型链查找,如果一层一层往上查,所有对象的原型最终都可以寻找到Object.prototype,Object构造函数的prototype

所有的对象都继承了Object.prototype上的属性和方法

读取属性和方法的规则: js引擎会先寻找对象本身的属性和方法,如果找不到,就到他的原型上去找,如果找不到,就到他的原型的原型上去找,如果直到最顶层的Object.prototype还是找不到,就会返回undefined

如果对象和他的原型定制了同名属性和方法,则本身的属性和方法优先,这也叫覆盖

function Person(name){
    this.name = name;
    this.showName = function(){
        console.log('jiejie')
    }
}
Person.prototype.showName = function(){
    console.log(this.name);
};
var p1 = new Person('john');
var p2 = new Person('jack');
p1.showName();

修改原型对象后constructor属性的注意点

一旦修改了构造函数的原型对象,一般情况下为防止引用出现问题,同时也要修改原型对象的constructor属性。

constructor属性表示原型对象和构造函数之间的关联关系

function MyArray(){};
MyArray.prototype=Array.prototype;
MyArray.prototype.constructor = MyArray;
var arr = new MyArray();
arr.push(1,2,3);
console.log(arr);

总结

//构造函数:Foo
//实例对象:f1
//原型对象:Foo.prototype
function Foo(){}
var f1 = new Foo();

//1.原型对象和实例对象的关系
console.log(f1.__proto__===Foo.prototype);//true

//2.原型对象和构造函数的关系
console.log(Foo.prototype.constructor===Foo);//true

//3.实例对象和构造函数
//没有直接关系
//间接关系:是实例对象可以继承原型对象的constructor属性
console.log(f1.constructor===Foo);//true

Foo.prototype={};
console.log(f1.__proto__===Foo.prototype);//false
console.log(Foo.prototype.constructor===Foo);//false

//所以代码的顺序很重要