学习日记 (2020-07-27) - 面向对象程序设计
面向对象程序设计
数据类型----Object类型:对象类型即一组数据和功能的集合。对象可以通过执行new操作符后跟要创建的对象类型的名称来创建。而创建Object类型的实例并为其添加属性或方法,就可以创建自定义对象。仅仅创建Object的实例并没有什么用处,但关键在于Object类型是其他的实例的基础。即Object类型所具有的任何属性和方法也同样存在于更具体的对象中。Object的每个实例都具有下列属性和方法。
1、constructor 保存着用于创建当前对象的函数
2、hasOwnProperty(“propertypeName”) 用于检查给定的属性在当前实例中(而不是实例的原型中)是否存在。
3、isPrototypeOf(object)用于检查传入的对象是否是传入对象的原型。
4 、propertyIsEnumerable(“propertypeName”):用于检查给定的属性是否能用于for-in来枚举。
5、toLocaleString()返回对象的字符串表示,该字符串与执行环境的地区对应。
6、toString()返回对象的字符串表示。
7、valueOf() 返回对象的字符串、数值或布尔值表示。
instanceof 检测对象类型。
一、工厂模式(简单了解即可):
function a(name,age){ var o = new Object() o.name =name; o.age = age; o.sayName = function () { alert(this.name) }; return o; } var person1 = a("Lee",12); var person2 = a("Lu",3);
person1 instanceof Object //true
//工厂模式没有解决对象识别的问题(即怎样知道一个对象的类型),所以构造函数模式产生了
二、构造函数模式:
像Object和Array这样的原生构造函数,在运行时会自动出现在执行环境。此外,也可以创建自定义的构造函数,从而自定义对象的类型和方法。
function Person(name,age){ this.name = name; //实例属性 this.age = age; this.sayName = function () { // 等价于 this.sayName= new Function (){"alert(this.name)"}
alert(this.name); //实例方法
}
}
var person1 = new Person("Lee",12); var person2 = new Person("Lu",3); alert(person1 instanceof Object) //true 是Object的实例。因为所以对象均继承自Object alert(person1 instanceof Person) //true 也是Person的实例
//person1、person2 分别 保存着Person的一个不同的实例。这2个对象都有一个
constructor(构造函数)属性,该属性指向Person.
person1.sayName = person2.sayName //false 作用域链不同
var b= new Object()
Person.call(b,'Lee',10) //call 或 apply
b.sayName() //Lee
要创建Person的新实例,必须使用new操作符。以这种方式调用构造函数实际会经历一下4个步骤:
(1)创建一个新对象。
(2)将构造函数的作用域赋给新对象。(因此this就指向了这个新对象)。
(3)执行构造函数中的代码(为这个新对象添加属性)。
(4)返回新对象。
三、原型模式:
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象(函数的原型对象),它的用途是包含可以由特定类型的所有实例共享的属性和方法。
function Box(){} Person.prototype.name ="Lee"; //原型属性 Person.prototype.age = "100"; Person.prototype.sayName = function () { //原型方法 alert(this.name) } var box1 = new Person() var box2= new Person() box1.sayName === person2.sayName // true
//将sayName()方法的所有属性字节添加给Box的property属性中,构造函数变成了空函数。
在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。Box.prototype.constructor指向Box。
创建自定义的构造函数后,其原型对象默认只会取得constructor属性,其他方法、属性都是从Object继承而来。
下图展示Box构造函数,Box的原型属性,以及Box现有的2个实例之间的关联、
Box.prototype指向了原型对象
Box.prototype.constructor指回Box
box1 box2都含有一个内部属性,该属性仅仅指向Box.prototype,换句话说,他们与构造函数没有直接的关系。

function Box(){
name1:'Li', //实例属性
sayName:function(){ //实例方法
alert(this.name1)
}
} Box.prototype.name ="Lee"; //原型属性 Box.prototype.age = "age"; Box.prototype.sayName = function () { //原型方法 alert(this.name) } var box1 = new Box() console.error(Box.prototype) console.error(box1.constructor) //得到构造函数本身 console.error(Box.prototype.constructor) //指向Box console.error(box1.constructor === Box) //true console.error(box1.prototype) //undefined
console.error(box1.__proto__)
// 如果是实例方法,不同的实例化,他们的方法(sayName)地址是不一样的 ,是唯一的。
// 如果是原型方法,那么方法sayName地址是共享的,大家都是一样的。
//判断一个对象实例是否指向了对象的原型对象,基本上只要实例化了,他是自动指向的。
alert(Box.prototype.isPrototypeOf(box1)) //true
alert(Array.prototype.isPrototypeOf(box1)) //false
//getPrototypeOf返回的对象实际就是这个对象的原型。
Object.getPrototypeOf(box1) == Box.prototype //true
Object.getPrototypeOf(box1).name // "Lee"
原型函数执行流程:
1、先查找构造函数实例里的属性或方法。如果有,立即返回。
2、如果构造函数实例里没有,则去他的原型对象里找,如果有,就返回。
虽然可以通过对象实例访问保存在原型中的值,但却不能访问通过对象实例重写的原型中的值。
function Box(){} Box.prototype.name ="lee"
var box1 = new Box() box1.name //"lee" 原型里的值 box1.name = "Jack" box1.name //“Jack” 就近原则 var box2 = new Box() box2.name //Lee, 原型里的值 没有被box1 修改
//如果想要box1可以访问原型对象的值,可以把构造函数里的属性删除即可。
delete box1.name //删除实例中的属性
box1.name //lee
delete Box.prototype.name //删除原型中的属性
Box.prototype.name ="Lily" //覆盖原型中的属性
box2.hasOwnProperty("name") //true 判断实例中是否存在制定属性
"name" in box2 //对象能够访问给定属性时返回true,无论属性存在于实例还是原型中,两边都没有返回false
function Box(){} Box.prototype.name ="Lee"; Box.prototype.age = "age"; Box.prototype.sayName = function () { alert(this.name) } // Object.keys(),返回一个包含所有可枚举属性的字符串数组。 var box1 = new Box() console.error(Object.keys(Box.prototype)) //["name", "age", "sayName"] box1.name = "Lili" console.error(Object.keys(box1)) //["name"]
//Object.getOwnPropertyNames() 返回所有实例属性的数组,无论是否可枚举
console.error(Object.getOwnPropertyNames(Box.prototype)) //["constructor", "name", "age", "sayName"]
更简单的源性方法
function Person () {}
//使用字面量的方式创建原型对象,这里{}就是对象,是Object。new Object 就相当于{} Person.prototype = { name:"Lee", age:20, sayName : function(){ alert(this.name) } } var friend = new Person () console.error(friend instanceof Object) //true console.error(friend instanceof Person) //true console.error(friend.constructor ==Person) //false console.error(friend.constructor ==Object) //true
constructor属性不在指向Person了。因为每次创建一个函数,就会同时创建它的prototype对象,
这个对象也会自动获得constructor属性。所以,新对象的constructor重写了Person原来的constructor,
因此会指向新对象,那个新对象没有指定构造函数,那么就默认Object。
function Box(){ } Box.prototype = { constructor :Box, //强制指向Box,也可以是其他对象,入:String,Number name :"Lee" }
var box = new Box()
box.constructor ==Box //true
function Box(){ } Box.prototype = {
name :"Lee" } //重写了原型对象 Box.prototype = { //这里不会保留之前原型的任何信息了。 age:"200" //把原来的原型对象和构造函数对象之间的关系切断了。 } var box = new Box()
box.name // undefined
function Person(){} var friend = new Person() Person.prototype = { constructor:Person, age :29 } friend.age //undefiend //重写原型对象切断了现有原型与任何之前已经存在的对象实例之间的联系。P157,图6-3
原生对象的原型:
原型模式的重要性不仅体现在创建自定义类型方面,就连所有原生的引用类型,都是采用这种方式创建的。所有原生引用类型(Object,Array,String等)都在其构造函数的原型上定义了方法。
Array.prototype.sort
Array.prototype.subString
//给基本包装类型String添加了一个名为startWith()的方法 String.prototype.startWidth = function (text) { return this.indexOf(text) ==0 } var msg = "Hello World" msg.startWidth("Hello") //true
浙公网安备 33010602011771号