一、面向对象基本特征
- 封装:也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
- 继承:通过继承创建的新类称为“子类”或“派生类”。继承的过程,就是从一般到特殊的过程。
- 多态:对象的多功能,多方法,一个方法多种表现形式。
- Javascript是一种基于对象(object-based)的语言。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)—–es6以前是这样的。所以es5只有使用函数模拟的面向对象。
二、对象实例化方式
-
字面量模式
var Car = { color: 'red', brand: '奔驰' } console.log(Car.color)
-
普通方式
var Car = new Object() Car.name = '三蹦子' Car.color = 'blue' Car.tyre = function () { console.log('我有三个轮子') } console.log(Car) Car.tyre()
-
构造函数方式
function Car(brand, color) { this.brand = brand this.color = color this.tyre = function () { console.log('我有三个轮子') } } var c1 = new Car('三蹦子', '蓝色') console.log(c1) c1.tyre()
缺点:每个函数都会开辟一块新的内存,造成内存浪费
解决方法:原型
三、构造函数注意事项
-
创造的Car可以称之为构造函数,也可以称之为类,构造函数就是类。
-
c1,c2均为Car构造函数的实例对象。
-
Car构造函数中的this指向Car的 实例对象即new Car()出来的对象
-
创建实例对象时必须带new
-
构造函数首字母大写,这是规范,请遵守它。如:Number() Array()
-
constructor:这是实例对象都自动含有的属性,指向他们的构造函数
console.log(c1.constructor === Car)//true
-
每定义一个函数,这个函数就带有一个prototype的属性,
__proto__
指向被实例化的构造函数的prototype,prototype默认带有constructor属性,constructor指向构造函数。
四、构造函数的问题
构造函数方法虽然好用,但是存在浪费内存的问题。对于每一个实例对象,tyre都是一样的内容,每一次生成一个实例,都必须 生成重复的内容,多占用内存。既不环保也缺乏效率。
function Car(brand, color) {
this.brand = brand
this.color = color
this.tyre = function () {
console.log('我有三个轮子')
}
}
var c1 = new Car('三蹦子', '蓝色')
var c2 = new Car('电动三轮', '白色')
console.log(c1.tyre === c2.tyre)//false
五、prototype原型
js中,每一个构造函数都又有一个prototype
属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。实例化的__proto__
指向构造函数的原型对象。
function Car(brand, color) {
this.brand = brand
this.color = color
}
Car.prototype.tyre = function () {
console.log('我有三个轮子')
}
var c1 = new Car('三蹦子', '蓝色')
var c2 = new Car('电动三轮', '白色')
console.log(c1.tyre === c2.tyre)//true
console.log(c1.__proto__ === Car.prototype)//true
总结:
- 构造函数有一个原型对象,通过pototype获取
- 构造函数创建 实例对象后,每个对象都有一个私有的
__proto__
属性,指向构造函数的原型对象
六、对象与构造函数的关系
对象是由构造函数造出来的
-
Object是Function 的一个实例。
Object.constructor == Function //true
-
函数是Function 的实例,但不是Object 的实例。
function fn(){} fn.constructor == Function //true fn.constructor == Object //false
-
{} 与 Object 的关系。
var obj = {}; obj.constructor === Object //true
七、静态成员和实例属性
-
实例成员:
实例成员就是构造函数的内部成员,实例成员只能通过实例化的对象来访问。每个实例成员只跟每个对象实例有关,不同对象实例成员是没有任何关系的
function Car(name, age) { this.name = name this.age = age } var c1 = new Car('花猫', 5) console.log(c1.name)//实例成员只能通过实例化对象访问
-
静态成员
静态成员在构造函数本身上添加的成员,与具体对象无关。只属于类不属于实例化对象
function foo(){ this.show = function(){ return this; } } foo.test = 123; //静态属性 foo.say = function(){ return this; } foo.say(); var fn = new foo(); //实例化的新的对象,this指向这个新的对象,不能访问类的静态方法 fn.say(); //Noname1.html:45 Uncaught TypeError: fn.say is not a function console.log(foo.say() == fn.say());
八、原型对象中this指向
构造函数中的this和原型对象的this,都指向我们new出来的实例对象
- 在构造函数中,this指向的是构造函数的实例
- 在构造函数的原型中,this同样指代的是构造函数的实例
function Car(bran) {
this.brand = bran
console.log(this);
}
Car.prototype.run=function(){
console.log(this);
}
var c1 = new Car('五菱宏光')
var c2 = new Car('长城皮卡')
c1.run()
c2.run()
九、继承call()方法
- call可以调用函数
- call可以修改this的指向,使用call()时,参数1是修改后的this指向,参数2,参数3。。。使用逗号隔开
调用函数
function Car() {
console.log(this)
}
Car.call()
改变this指向
function Car() {
console.log(this)
}
function Car2() {
this.name = name
}
var c1 = new Car2()
Car.call(c1)
改变this指向并传参
function f1(name, age) {
console.log(this)
this.name = name
this.age = age
this.speak = function () {
console.log('我叫'+this.name, '今年'+this.age)
}
}
function Person() {
this.name = name
}
var p1 = new Person()
f1.call(p1, 'GRH', 21)
p1.speak()
1、子构造函数继承父构造函数中的属性
function Parent(name, age) {
console.log(this)
this.name = name
this.age = age
}
function Chinese(name, age, hukou) {
Parent.call(this, name, age)
this.hukou = hukou
}
var f = new Parent('grh', 18)
console.log(f)
var f1 = new Chinese('grh', 18, '沧州')
console.log(f1)
2、借用原型对象继承方法
function Father(name, age) {
this.name = name
this.age = age
}
Father.prototype.speak = function () {
console.log('哈哈哈')
}
function Son(name, age, score) {
Father.call(this, name, age)
this.score = score
}
Son.prototype = new Father()
Son.prototype.constructor = Son
Son.prototype.exam = function () {
console.log('我的成绩不错')
}
var son = new Son('grh', 21, 100)
console.log(son)