javascript高级程序设计学习笔记(一)---面向对象

面向对象

对象

数值属性

  • 四个属性

    • configurable

      表示可否删除属性

    • enumerable

      表示是否可以循环属性

    • writable

      表示是否可写

    • value

      属性的值

访问器属性

通过Object.defineProperty定义
两个参数:
第一个对象是要添加和修改其属性的对象,第二个对象的属性与第一个对象中要添加或修改的属性意义对应

  • configurable

    扫描二维码关注公众号,回复: 12390319 查看本文章

    通过delete删除属性从而重定义属性

  • enumerable

    通过for-in循环返回属性

  • get

    读取属性调用,默认为undefined

  • set

    写入·属性调用,默认为undefined

创建对象

工厂模式

function createPerson(name,age,job){
    
    
	var Person = new Object();
	Person.name=name;
	Person.job = job;
	Person.age = age;
	Person.sayName = function(){
    
    
	}
	return Person;
}

在进行实例化,因此在以上方式中,相当于Person是一个·工厂,预先定义了属性和方法,需要创建的实例只需要调用该函数并且附上相应的实参,就可以创建一个新的对象实例
但是该方法没能实现对象识别

使用构造函数

function Person(name,age,job){
    
    
	this.name = name;
	this.job = job;
	this.age = age;
	this.sayName = function(){
    
    
		alert(this.name)
	}
}

创建一个新对象
将构造函数的作用域赋给新对象(this指向这个新对象)
执行构造函数中的代码
返回新对象

实例化:
通过new调用
var person1 = new Person(‘ss’,11,‘faa’);

检测对象类型:
person1 instanceof Object
person1 instanceof Person

构造函数当作函数:
在普通函数中调用:window.sayName()
在另一个对象的作用域中调用:

var O = new Object()
				Person.call(O,"fa",123,"few")
				O.sayName()
2.问题,每次都有重新定义方法,因此可以把方法抽离出来:
function Person(name,age,job){
    
    
	this.name=name;
	this.job = job;
	this.age = age;
	this.sayName = sayName
}
function sayName(){
    
    
alert(this.name)
}

原型模式

prototype属性,指向一个对象,这个对象包含可以有特定类型的所有实例共享的属性和方法

prototype的创建伴随新函数的创建,所有原型对象自动获得一个constructor属性,包含一个执行prototype属性的指针。Person.prototype.constructor指向Person。_proto_存在于·实例和构造函数的原型对象之间
Person.prototype指向了原型对象,Person.prototype.constructor指向了Person,实例不包含属性和方法,当视可以调用person1.sayName,这是通过查找对象属性的过程实现的。读取某个对象某个属性时,执行一次搜索,先从实例本身开始,如果实例中照道理具有给定名字的属性,返回该属性的值;没有找到,则继续搜索指针指向的原型对象,在原型对象中找具有给定名字的属性,找到就返回。
不可以通过实例重写原型中的值,如果新添属性和原型中一个属性同名,那么在实例中创建该属性,并且屏蔽掉原型中的属性。使用hasOwnProperty()检测属性是存在原型还是实例重,在实例用返回true。

原型的简单语法:使用对象字面量
调用构造函数时会为实力添加一个指向最初原型的[[Prototype]]指针,而把原型修改为另一个对象就等于切断了构造函数与最初原型之间的联系。实例中的指针仅指向原型,不指向构造函数。
所有原生引用类型都在其构造函数的原型定义了方法,通过原生对象的原型,可以取得所有默认方法的引用,而且可以定义新的方法

原型对象的问题:忽略了为构造函数传递初始化参数的这一环节,所有所有实例在默认情况下都将取得相同属性值。而且共享属性会导致本意愿私有化的引用类型的属性被同时修改,多个实例没办法单独使用一个属于自己的全部属性。

组合使用构造函数和原型模式

构造函数用于定义实例属性,原型模式用于定义方法和共享的属性

寄生构造函数模式

创建一个函数,该函数仅仅是封装创建对象的代码,然后返回新创建的对象。与构造函数相似,只不过可以通过return重定义返回值。

继承

原型链

利用原型链让一个引用类型继承另一个引用类型的属性和方法。每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。如果我们让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型对象的指针。相应的,另一个原型中也包含着一个指向另一个构造函数的指针,如此层层递进。

定义两个类型:Super和Sub,而且Sub继承了Super。继承是通过创建Super的实例,并将该实例赋给Sub.prototype实现的,实质就是重写原型对象,代之以一个新类型的实例。所有最终Sub的实例的内部指针指向Sub的原型,Sub的原型又指向Super的原型。

因此在原型链下,搜索步骤:
1、搜索实例;
2、搜索Sub.prototype;
3、搜索Super.prototype,最后一步才会找到该方法。

所有函数默认原型都是Object的实例,默认原型都会包含一个指向Object.prototype的内部指针
如果子类有时候需要重写(超类型中的)或者添加方法(超类型没有的),添加方法的代码一定要放在替换原型的语句之后
存在问题:在通过原型来实现继承时,原型实际上会变成另一个类型的实例,于是原先的实例属性也就顺理成章变成了现在的原型属性,这个属性可以呗Sub所有私立共享

另外一个问题就是:在创建子类型的时候,不能向超类型的构造函数传递参数

借用构造函数

在子类型构造函数的内部调用超类型构造函数。例如可以在Sub内部使用Super.call(this)。可以解决原型链问题一,时每个实例都具有自己的属性副本
可以在子类型构造函数中向超类型构造函数传递参数

function Super(name){
    
    
    this.name = name
}

function Sub(){
    
    
    Super.call(this,'jack')
    // 实例属性
    this.age = 20
}

var sub1 = new Sub()
alert(sub1.name)
alert(sub1.age)

组合使用两种方法

使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承

function Super(name){
    
    
    this.name = name
    this.colors = ['red']
}

Super.prototype.sayName = function(){
    
    
    alert(this.name)
};

function Sub(name,age){
    
    
    Super.call(this,name);
    this.age = age;
}

Sub.prototype = new Super()
Sub.prototype.sayAge = function() {
    
    
    alert(this.age)
}

寄生继承及组合使用

创建一个仅用于封装继承过程的函数,该函数在内部以某种给方式来增强对象,最后返回对象

在组合使用寄生式继承时,通过借用构造函数来继承属性,通过原型链来继承方法。不必为了指定子类型的原型而调用超类型的构造函数,只需要一个超类型的副本而已,实际上时使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。因此在这个函数中,第一步可以先创建超类型的一个副本,第二部就是为创建的副本添加constructor属性,从而弥补重写原型而失去的默认的constructor属性。最后就将新创建的对象赋值给子类型的原型。如下:

function inheritPro(sub, superr){
    
    
    var prototype = object(superr)
    prototype.constructor = sub;
    sub.prototype = prototype
}

function Super(name){
    
    
    this.name = name
    this.colors = ['red']
}

Super.prototype.sayName = function(){
    
    
    alert(this.name)
};

function Sub(name,age){
    
    
    Super.call(this,name);
    this.age = age;
}

inheritPro(Sub,Super);
Sub.prototype.sayHi = function (){
    
    
    alert(this.age)
}

在上面中,只调用了一次Super构造函数,避免两次调用造成属性的重写覆盖。同时,原型链还能保持。

猜你喜欢

转载自blog.csdn.net/ningpeixi679/article/details/112912332