《JavaScript高级程序设计》OOP章节的总结

从去年开始阅读红宝书,从第一遍看不懂,到后来慢慢理解,这个过程仍是很痛苦的(已经粗略翻看了6遍了o(╥﹏╥)o),因此忽然打算记录下看书学习过程当中总结的笔记,并抽这个空再一次回顾下基础知识,对于我来讲,每看一遍感受都是不同的,都会有很大的收货(前端路漫漫o(╥﹏╥)o)javascript

p为Person的实例化对象 / var p =new Person()前端

方法 做用
instanceof 检测对象是否为另外一个对象的实例 p instanceof Person
isPrototypeOf 没法访问[[Prototype]] 可使用isPrototyprOf()来肯定是否存在这种关系 Person.prototype.isPrototypeOf(p)
Object.getPrototypeOf() 能够获取一个实例对象的原型 Object.prototypeOf(p)==Person.prototype
hasOwnProperty p.hasOwnProperty('name') true来自实例 false说明来自原型
Object.getOwnPropertyDescriptor() 只能用于实例属性获取,要想取得原型属性的描述符,必须直接在原型对象上调用此方法
Object.keys() 接受一个对象的参数,返回一个包含全部可枚举属性的字符串数组
Object.getOwnPropertyNames() 返回的全部实例属性,枚举和不可枚举都有 Object.getOwnPropertyNames(Person.prototype)
Object.create() 参数是一个做为新对象原型的对象和一个为新对象定义额外属性的对象
更多 更多

1. ECMA两种属性类型

数据属性
configurable  默认true
    1.表示能都否经过delete删除属性而从新定义属性,
    2.可否修改属性的特性,
    3.可否把属性修改成数据属性  
enumerable  
     表示可否使用for-in循环返回属性   默认true
get   
     表示读取属性时调用	默认 undefined
set  
	 表示写入属性时调用   默认undefined

复制代码

vue.js中就是采用此方法,因此不支持IE8vue

当对象里面有属性,采用Object.defineProperty方法只是修改特性和值时,默认值都为true,java

访问器属性
configurable  默认true
    1.表示能都否经过delete删除属性而从新定义属性,
    2.可否修改属性的特性,
    3.可否把属性修改成数据属性  
enumerable
    表示可否使用for-in循环返回属性  默认true
get 
    表示读取属性时调用	默认 undefined
set 
    表示写入属性时调用 默认undefined

复制代码
案例
/* 数据属性:定义了一个对象Person 其中name的属性指定的值就是[[value]]的值 ,这个值的任何修改情况都将反映在value数据属性的特性上 */

var Person={
	name:"梵高先生"
};

/* 要修改默认的特性,必须使用ES5的Object.defineProperty()方法 arguments参数为 1.属性所在的对象, 2.属性的名字, 3.一个描述符(descriptor)对象(属性必须是其中之一或多个) Object.defineProperty(Person,'name',{ value:"达芬奇" // /提示:咱们能够手动进行修改,此时Person.name="达芬奇" }) */

Object.defineProperty(Person,'name',{
	writable:false,   //表示可否修改属性值
    // configurable:false 一旦把属性定义为不可配置的,就再也没法改变回来; 可屡次调用方法修改同一个属 性,可是configural设置为false后就会有限制了
}) 

console.log(Person.name)  //梵高先生
Person.name="莫扎特先生"  //若是上面设置了writable为false后,属性value的值不会被修改
console.log(Person.name)  //梵高先生


/* 访问器属性 _variable表示只能经过对象访问的属性 */

var book={
	_year:2004,
	edition:1
}
Object.defineProperty(book,'year',{
	get:function(){
		return this._year;
	},
	set:function(newValue){
		if(newValue>2004){
			this._year=newValue;
			this.edition=this.edition+(newValue-2004);
		}
	}
})

book.year=2008;
console.log(book.edition)  //5


复制代码
定义多个属性defineProperties
/* 定义多个属性 Object.defineProperties(obj,{props}) 参数一为要修改属性的对象,参数二为要修改的属性对象 读取属性的特征 Object.getOwnPropertyDescriptor(obj,描述符对象的属性) */

var book={};
Object.defineProperties(book, {
	_year:{
		// writable:true,
		value:2004
	},
	edition:{
		writable:true,
		value:1
	},
	year:{
		get:function(){
			return this._year
		},
		set:function(newValue){
			if(newValue>2004){
				this._year=newValue;
				this.edition+=newValue-2004
			}
		}
	}
})

book.year=2008;
console.log(book.edition) //5
var descriptor1=Object.getOwnPropertyDescriptor(book, "_year")
console.log(descriptor1)

/* {value: 2004, writable: false, enumerable: false, configurable: false} configurable: false enumerable: false value: 2004 writable: false __proto__: Object */
var descriptor2=Object.getOwnPropertyDescriptor(book, "edition")
console.log(descriptor2)

/* {value: 5, writable: true, enumerable: false, configurable: false} configurable: false enumerable: false value: 5 writable: true __proto__: Object */
var descriptor3=Object.getOwnPropertyDescriptor(book,"year")
console.log(descriptor3)

/** {get: ƒ, set: ƒ, enumerable: false, configurable: false} configurable: false enumerable: false get: ƒ () set: ƒ (newValue) __proto__: Object */

复制代码

2. 建立对象

对象字面量和Object()
var person=new Object();
person.name="cc"

//便于收编属性,
//方便函数传参调用
var person={
    name:"cc"
}

复制代码

3. 工厂模式(常见)

ECMA没法建立类(ES6支持Class),利用函数封装一特定接口建立对象的细节,虽然解决了建立对象的问题,可是没有解决如何知道对象的类型python

/* 工厂模式:抽象了建立具体对象的一过程 缺点:没法知道一个对象的类型(对象识别的问题) */
function createPerson(name,age){
	var obj= new Object();
	obj.name=name;
	obj.age=age;
	obj.say=function(){
		console.log(this.name)
	}
	return obj
}
var person=createPerson("梵高先生",20);
person.say()

复制代码

4. 构造函数(常见)

  1. 没有显示的建立对象
  2. 直接将属性和方法赋给this
  3. 没有return对象
/* 使用构造函数会经历如下四个过程 1.建立一个新对象 2.将构造函数的做用域赋给新的对象 所以this就指向这个对象 3.执行构造函数中的代码 也就是给新对象添加属性 4.返回新的对象 缺点: 1.每一个方法都要在不一样的对象实例中建立一次,形成没必要要的资源浪费 (函数也是对象Function,每次new的时候都会建立一次) */

function Person(name,age,food){
	this.name=name;
	this.age=age;
    this.food=food;
    this.say=function(){  //每次建立实例都会调用,形成没必要要的资源浪费 
        console.log(this.name)
    }
    this.eat=eat;   //会致使定义多个全局函数
}
/* obj1和obj2共享一个全局做用域中的函数eat 问题思考:调用时候是被对象调用,全局做用域名副其实,会致使定义多个全局函数 */
function eat(){
	console.log(this.food)
}
var obj1=new Person("我是对象一",10,'米粉');
var obj2=new Person("我是对象二",20'花甲')
obj1.eat()
obj2.eat()
console.log(obj2.constructor===Person)


/* 问题详细补充: 1.把构造函数当作函数, - 也就是说任何函数只要经过new操做符调用,咱们均可以称之为构造函数 - 若是不使用new做为普通函数调用,则调用结果会指向全局window对象 - 在另外一个对象做用域中调用 Person.call(实例,属性1,属性2....) 2. 构造函数的问题 this.sayName=new Function() 以这种方式建立函数,会致使不一样的做用域链和标识符解析。建立机制相同,因此不一样实例的sayName是不相等的,因此开销也比较大,咱们能够在外部定义方法(咱们将对象方法写在了全局做用域中),一样带来了问题,在全局中的方法实际是被某个对象调用,这让全局做用域有点 对不上号,若是须要定义不少方法,就要定义不少全局函数,因此面向对象丝毫没有封装可言,因此咱们能够经过下一节的原型模式解决 */
复制代码

5.原型模式(常见+重点)

  1. 每一个函数都有一个原型属性prototype,这个属性是一个指针,指向一个对象数组

  2. 这个对象包含有特定类型的全部实例共享的属性和方法浏览器

理解原型对象
/* 1. 原型对象默认会拥有constructor属性指向构造函数 Person.prototype.constructor==Person //true 2. __proto__ 隐式属性 存在实例和构造函数的原型对象之间 ,而不是实例和构造函数之间 p.__proto__==Person.prototype //true 3. 一旦给实例设置了属性,就会阻止咱们访问原型对象中的同名属性 一旦使用delete删除了属性,就会恢复原型对象的连接 */
function Person(name,age,sex){
    this.name=name;
    this.age=age;
    this.sex=sex;
    this.sayName=function(){
        console.log(this.name,this.sex,this.sex);
    }
}
Person.prototype.address="aaa"
var p=new Person('cc',18,'男');
p.address="bbb"  //就会阻止咱们访问原型对象中的同名属性 
console.log(p.addesss) //bbb而不是aaa
delete p.address;
console.log(p.addesss)  //恢复原型对象的连接 aaa
/* 换句话说,添加的属性只会阻止咱们访问原型中的属性,但不会修改那个属性,即便是添加属性设置为null,,也 只在实例中设置,并不会恢复指向原型的连接,咱们可使用delete彻底删除实例属性 */
复制代码
原型与in操做符
  1. in操做符安全

    //肯定一个属性是原型属性
    function hasPrototypeProperty(object,name){
        return !object.hasOwnProperty(name)  && (name in object)
    }
    var person=new Person("cc");
    Person.prototype.id=123
    hasPrototypeProperty(person,'id') // 存在原型中
    复制代码
  2. for inapp

    返回全部可以经过对象访问和可枚举的属性,其中包括存在实例和原型中的属性函数

    ie8中及更早版本,存在bug:屏蔽不可枚举属性的实例属性不会出如今for..in循环中

更简单的原型语法(重写原型)

前面每次添加原型属性都要使用 Person.prototype,每次都要写一遍,为了减小没必要要的输入,咱们能够经过对象字面量来重写原型对象(收编),从视觉上更好的封装原型的功能

注意点: 这种作法会致使 constructor属性再也不指向Person了,由于原型对象被重写了,尽管instanceof能检查实例,可是constructor以及没法肯定对象类型了

function Person(name,age,sex){
    this.name=name;
    this.age=age;
    this.sex=sex;
    this.sayName=function(){
        console.log(this.name,this.sex,this.sex);
    }
}
/* 原型对象被重写,constructor属性再也不指向Person了,咱们能够手动重置constructor 可是这种重设置会致使 [[Enumerable]]特性被设置为true,默认constructor属性是不可枚举的 */
Person.prototype={
    // constructor:Person,
    address:"地址"
}
var p=new Person('cc',18,'男');


/* 若是设置兼容性则可使用Object.defineProperty(),重设构造函数,只适用用ES5兼容的浏览器 */
Object.defineProperty(Person.prototype,"constructor",{
    enumerable:false,   //默认constructor属性是不可枚举的
    value:Person
})
复制代码
原型的动态性

在原型中查找值的过程是一次搜索,因此对原型对象作任何修改都会当即从实例上反映出来,

例:在生成实例代码后面(代码顺序),咱们在原型对象上建立一个方法,结果依然能调用,由于实例和原型之间的松散链接关系

var p=new Person();//生成实例
Person.prototype.say=function(){   //生成实例代码后面添加
    console.log(this.name)
}
p.say() //结果依然能调用
复制代码

当咱们调用构造函数建立实例时,js会给实例添加一个指向最初原型的 [[prototype]]指针,若是对象字面量重写原型,就切断了这个实例和原型的关系,而指向Object

原生对象的原型 Object,Array,String

不推荐修改原型以及扩展方法,会致使冲突,也有可能 重写原生对象的方法

原型模式的问题

问题: 因为原型对象的共享性致使的,函数(方法)可使用,基本值类型也说得过去,可是使用引用类型值的属性时,问题就比较突出了 (原型对象中使用引用数据类型的问题 )

要共享相同基本数据(如数组)没什么问题,可是实例通常都是有本身单独的属性的,这也就是没人单独使用原型模式的问题的缘由所在

6. 组合使用构造函数模式和原型模式(常见)

建立自定义类型最多见的方式就是 组合使用构造函数模式和原型模式 ,这是在ECMAScript中使用最为普遍,认同度最高的一种建立自定义类型的方法,也能够说是定义引用类型的一种默认模式

  1. 构造函数用于定义实例属性
  2. 原型模式用于定义方法和共享的属性
/* 好处: 1.每个实例都会有本身的一份实例属性的副本,但同时有共享者对方法的引用,最大限度的节省了内存 2.这种混合模式还支持向构造函数中传递参数,可谓是集两者之长 */

function Person(name,age,obj){
    this.name=name;
    this.age=age;
    this.sex=obj;
    this.friends=['cc01','cc02'];
}
Person.prototype={  //重写了原型Person.prototype,
    constructor:Person,  //须要手动重置constructor (Person.prototype.constructor==Person)
    sayName:function(){
        console.log(this.name)
    }
}
var person01=new Person("张三",18,'前端开发');
var person02=new Person("李四",20,'java后台');
person01.friends.push("cc03");
console.log(person01.friends); // ["cc01", "cc02","cc03"]
console.log(person02.friends) // ["cc01", "cc02"]
复制代码

7.动态原型模式(常见)

以前组合使用构造函数和原型模式时,两者都是分别单独定义的 。使用动态原型模式能够将全部信息都封装在构造函数中的,而经过在构造函数中初始化原型(必要状况下),又同时使用构造函数和原型的优势

function Person(name,age,job){
    this.name=name;
    this.age=age;
    this.job=job;
    if(typeof this.sayName != 'function'){   //添加方法
        Person.prototype.sayName=function(){
            console.log(this.name)
            //注意点: 使用此模式不能使用对象字面量重写原型对象,已经建立了实例的状况下而后去重写原型,会切断新的原型对象和实例之间的联系
        }
    }
}
var person=new Person("cc",18,'前端开发')
person.sayName() //cc

复制代码

8.寄生构造函数模式

场景: 前面几种模式都不适用的状况下可使用此模式

基本思想:建立一个函数,做用仅仅是封装建立对象的代码,而后返回新建立的对象

/* 注意点: 寄生构造函数模式,返回的对象和构造函数或者与构造函数的原型对象没有任何关系,也就是说 构造函数返回的对象与在构造函数以外建立的对象没有什么不一样, instanceof检测无心义, 因此因为这些问题,建议在使用其余模式的状况下不要使用这种模式 */

function Person(name,age,job){
    var o=new Object();
    o.name=name;
    o.age=age;
    o.job=job;
    o.sayName=function(){
        console.log(this.name)
    }
    return o;
}
var person01=new Person("cc",18,'java')


// 在特殊场景下用来建立构造函数,假设增长一个数组方法,不能修改Array的构造函数状况下,咱们能够本身使用这个模式建立
function SpecialArray(){
        //建立数组
        var values=new Array();
        //添加值 
        values.push.apply(values,arguments);  //用构造函数接受到的全部参数 这里使用arguments对象
        //添加方法
        values.toPipedString=function(){
            return this.join("|")
        }
        //返回数组
        return values
    }
var colors=new SpecialArray('red','green','blue')
console.log(colors.toPipedString())  //red|green|blue
复制代码

9.稳妥构造函数模式

所谓稳妥就是 没有公共属性,并且其方法也不引用this的对象 ,最适合在一些安全的环境中(会禁用this和new),或者在防止数据被其余应用程序改动时使用

/* 稳妥构造函数模式遵循与寄生构造函数模式相似的模式 不一样之处: 1.新建立对象的实例不引用this 2.不适用new操做符调用构造函数 和寄生构造函数模式同样,返回的对象和构造函数或者与构造函数的原型对象没有任何关系, 因此instanceof操做符没意义 */

function Person(name,sex,job){
        var o=new Object();
        //这里能够添加定义 私有变量和函数
        o.name='cc'
        o.sayName=function(){ 
            console.log(name)  //只有经过此方法才能访问到name
        }

        return o;
    }
var person=Person("cc",12,'python')  //person保存的是一个稳妥对象
person.sayName()
复制代码

10. 继承(重点)

OOP预语言都支持两种方式的继承:

  1. 实现继承:是指继承实际的方法
  2. 接口继承 :只继承方法的签名,ECMAScript没有函数签名,因此只能支持实现继承
原型链继承

基本思想是利用原型让一个引用类型继承另外一个引用类型的属性和方法

原型,构造函数,实例三者关系 :

  1. 每一个构造函数都是一个原型对象,原型对象都包含一个指向构造函数的指针(constructor)
  2. 每一个实例都包含一个指向原型对象的内部指针(proto)
function SuperType() {
      this.property = "我是父类属性"
  }
SuperType.prototype.getSuperValue = function() {
    return this.property;
}
function SubType() {
    this.property = "我是子类属性"
}
/* SubType继承了SuperType,实现继承的本质是重写原型对象,用新类型的实例代替(替换原型) 新原型拥有SuperType实例所拥有的全部属性和方法,其中内部指针__proto__也指向SuperType的原型对象 new SuperType()-->SubType.prototype-->SuperType.prototype */
SubType.prototype = new SuperType(); 
//添加新的方法
SubType.prototype.getSubProperty = function() {  
    return this.property; //实例属性和原型方法
}
//重写父类型中的方法
SuperType.prototype.getSuperValue = function() {
    return false
}
var instance = new SubType();
console.log(instance)   //SubType{property}
console.log(instance.__proto__)  //SuperType{property,getSubProperty}
console.log(instance.constructor) //指向SuperType是由于SubType.prototype中的constructor被重写了
console.log(instance.getSubProperty()) //我是子类属性
console.log(instance.getSuperValue()) //false
复制代码

总结:

  1. 别忘了默认的原型是Object,SubType继承了SuperType.SuperType又继承了Object

  2. 肯定原型和实例的关系

  3. 谨慎定义方法 覆盖和添加方法时必定要放在替换原型的语句以后 ,也不要使用对象字面量建立原型的方法,

    这样会重写原型链

  4. 原型链的问题

    1.包含引用原型的原型属性会被全部实例共享,(为何定义在构造函数中,而再也不原型中定义属性)
    2.建立子类型的实例时,不能向父类型的构造函数中传递参数,因此实际不多会单独使用原型链
    复制代码
借用构造函数

解决原型对象中包含引用类型值所带来的问题,使用一种叫作 借用构造函数的模式 (伪造对象或经典继承)

实现方式:在子类型构造函数的内部调用父类型构造函数 (记住:函数只不过是在特定环境中执行代码的对象),而后使用apply()和call()能够在未来建立的对象上执行构造函数

/* 好处: 相对与原型链来说,借用构造函数很大的优点是能够 在子类型中构造函数中能够向父类型构造函数中传递参数 问题: 若是仅借用构造函数,那么就没法避免构造函数模式所存在的问题----方法都在构造函数中定义,函数的复用就无从谈起,因此不多是单独使用的 */

function Person(name) {
      this.colors = ['a', 'b', 'c'];
      this.name = name //还能够经过call传递参数
 }

function Student() {
    Person.call(this, 'EastBoat') 
   // Person.apply(this, ['EastBoat']) 
    //表示在将来将要建立的新对象(实例)person01和person02的各自环境中调用Person的构造函数,各自都会有本身的副本了,互不影响,同时传递了参数
}

var person01 = new Student()
person01.colors.push("fff", 'ggg');
console.log(person01.colors) //["a", "b", "c", "fff", "ggg"]
console.log(person01.name)
var person02 = new Student();
console.log(person02.colors) //["a", "b", "c"]
console.log(person02.name)
复制代码
组合继承

也叫做伪经典继承:将原型链和构造函数组合在一块儿使用,从而发挥两者之长的一种继承模式

/* 思想: 使用原型链实现对原型属性和方法的继承, 经过借用构造函数实现对实例属性的继承 做用: 经过在原型对象上定义方法实现了函数复用,又能保证每一个实例都有他本身的属性 优势: 避免了原型链和借用构造函数的缺陷,融合了他们的优势,成为javascript中最经常使用的继承模式 instanceof和isPrototypeOf()也可以识别基于组合继承建立的对象 缺点 不管什么状况下,都会调用两次父类型的构造函数, 第一次:建立子类的原型的时候 SubType.prototype=new SuperType() 第二次:在子类的构造函数内部 SuperType.call(this) 第一次调用SubType.prototype会获得两个属性,自己他们是SupperType的实例属性,如今位于子类原型SubType.prototype中 第二次调用SubType构造函数时----call(this),此时又会调用SuperType构造函数,此时生成SubType属性,就自动屏蔽了第一次SubType的原型 */

function SuperType(name, age) {
     this.name = name;
     this.age = age;
     this.hobby = ['篮球', '唱歌'];
 }
SuperType.prototype.sayHobby = function() {
    console.log(this.hobby)
}
function SubType(name, age) {
    SuperType.call(this, name) //继承父类属性
    this.age = age;
}
SubType.prototype = new SuperType(); //继承方法
SubType.prototype.sayAge = function() {
     console.log("我是SubType的原型方法" + this.age)
}
var p1 = new SubType('p1', 22);
p1.hobby.push("羽毛球")
p1.sayHobby();
p1.sayAge()

var p2 = new SubType("p1", 18);
console.log(p2.hobby);
p2.sayHobby();
p2.sayAge()
复制代码
原型式继承

没有使用严格意义上的构造函数,借助原型能够基于已有的对象建立新对象,同时还没必要所以建立自定义类型

整个过程和Object.create(person)同样,是建立了对象的一个副本

这种方式比较少 ,缘由就是和原型链继承同样,引用数据类型容易改变

function object(o) {
    function F() {} //临时性构造函数
    F.prototype = o; //传入的对象做为这个构造函数的原型
    return new F() //返回临时类型的一个新实例
}

/* 本质上,object()对传入其中的对象执行了一次浅复制, 要求你必须有一个对象能够做为另外一个对象的基础, 下面的案例中,能够做为另外一个对象基础的是Person对象,咱们将其传入到object函数中,而后就返回出一个新的对象 */
var person={
    name:"cc",
    food:['a','b','c']
}

var p1=object(person)
p1.name='p1';
p1.food.push('dddd');
console.log(person.food);  //["a", "b", "c", "dddd"]

var p2=object(person);
p2.name="p2";
p2.food.push("eeee")
console.log(person.food);  //["a", "b", "c", "dddd", "eeee"]
复制代码
寄生式继承

寄生式继承在原型式继承的基础上增长了本身的方法。

/* 与原型式继承密切相关的一种思路 相似: 寄生构造函数和工厂模式 缺点: 为对象添加函数,因为没法作到函数复用而下降效率,这一点和构造函数模式相似 */
function object(o) {
     function F() {}
     F.prototype = o;
     return new F();
 }

function createAnother(original) {
    //调用函数建立一个新对象,此处object不是必须的,任何可以返回新对象的函数都适用此模式
    var cloneObj = object(original); 
    cloneObj.sayHi = function() {  
        console.log('hihihiih')
    }
    return cloneObj;
}

var person = {
    name: "cc",
    hobby: ['a', 'b', 'c']
}

var anotherPerson = createAnother(person);
console.log(anotherPerson)  //hihihiih
anotherPerson.sayHi()
复制代码
寄生组合式继承(最理想 )

组合继承并非最好的继承,由于经过将构造函数的原型指向父构造函数的实例,会两次调用构造函数 ,前面已经讲了组合继承的缺点,咱们没必要为了指定子类的原型对象而去调用父类的构造函数,咱们无非只须要父类型的一个副本而已,

优势:

  1. 高效体如今这种模式只调用了一次superType构造函数,而且所以避免了在SubType.prototype上建立没必要要的,多余的属性
  2. 与此同时,还能保证原型链不变,还可以正常使用instanceof和isPrototypeOf()
/* 解决组合继承中两次调用superType构造函数的问题,其方法是在中间架一座桥梁(加一个空的构造函数) 另外不能直接将SubType.prototype指向SuperType.prototype是由于会引用相同的内存,形成共享,因此要指向实例。 实际过程以下: 中间桥梁为空的构造函数,后面注释为object()函数的实现过程,也可以使用Object.create() function Temp(){ } // function F() { } Temp.prototype=SuperType.prototype; // F.prototype = SuperType.prototype var temp=new Temp(); // var prototype=new F(); ///建立对象 temp.constructor=SubType // prototype.constructor = SubType; //加强对象 SubType.prototype=temp; // SubType.prototype = prototype //指定对象 */

 function object(o) {
     function F() { }
     F.prototype = o;
     return new F();
 }
function inheritPrototype(subType, superType) {
      var prototype = object(superType.prototype); //建立对象 
      //var prototype = Object.create(superType.prototype); //ES5新增方法
      prototype.constructor = subType; //加强对象
      subType.prototype = prototype //指定对象
  }
//父类构造器
function SuperType(name) {
    this.name = name;
    this.colors = ['res', 'yellow', 'green']
}
SuperType.prototype.sayName = function () {
    console.log(this.name)
}

//子类构造器
function SubType(name, age) {
    this.name = name;
    this.age = age;
}
inheritPrototype(SubType, SuperType)  //继承实现 

SubType.prototype.sayAge = function () {
    console.log(this.age)
}

//重写原型对象方法sayName
//SubType.prototype.sayName = function () {
// console.log("bb")
//}

var p = new SubType("cc", 18);
p.sayAge(); //18
p.sayName()//cc 若是重写原型对象方法,打印就是'bb'
复制代码
相关文章
相关标签/搜索