面向对象编程(oop):具有灵活,代码可复用性,高度模块化等特点
对象是什么
对象是单个实物的抽象,对象是一个容器,封装了对应的属性和方法。属性是对象的状态,方法是对象的行为。
构造函数
用来初始化新创建对象的函数
生成对象
需要一个模板(表示一类实物的共同特征),让对象生成。类就是对象的模板,但js不是基于类的,而是基于构造函数(constructor)和原型链(prototype)的。
//Dog是构造函数,为了区别于普通函数,首字母大写
function Dog(name,age){
//name和age就是当前实例化对象的属性
this.name = name;
this.age = age;
}
var huahua = new Dog('huahua',3);
构造函数的特点
- 函数体内使用this,代表了所要生成的对象实例。
- 生成对象,必须使用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
//所以代码的顺序很重要