继承模式,命名空间,对象枚举

(一) 继承模式

  1. 传统形式(原型链)

(1) 缺点:过多的继承了没用的属性

(2) 代码展示


//缺点:过多的继承了没用的属性

Grand.prototype.lastName = ‘张‘;

function Grand(){

this.name = ‘国庆‘;

}

var grand = new Grand();

Father.prototype = grand;

function Father(){

this.name = ‘改革‘;

}

var father = new Father();

Son.prototype = father;

function Son(){

this.name = ‘小宝‘;

}

var son = new Son();

//son这里只想用Grand.prototype上的属性,可是这样一继承,不但继承了Grand.prototype上的属性,

// 也继承了一些不必要的属性,如father上的属性

  1. 借用构造函数(call/apply)

(1) 缺点:① 只能继承借用函数的方法和属性,不能用他的原型

② 每次构造函数都要多走一个函数

(2) 代码展示


function PersonOne(name,age,sex){

this.name = name;

this.age = age;

this.sex = sex;

}

function PersonTwo(name,age,sex,color){

//var this = { __proto__:PersonTwo.prototype }

PersonOne.call(this,name,age,sex);

this.color = color;

}

var person1 = new PersonTwo(‘小李‘,23,‘男‘,‘blue‘);

console.log(person1);

  1. 共享原型

(1) 缺点:不能随便改变自己的原型,因为自己的原型和原来的函数用的是 一个原型,自己的改,原来的相应的也会去改

(2) 代码展示:


//共享原型封装

function inherit(Target,Origin){

Target.prototype = Origin.prototype;

}

//应用

Father.prototype = {

name:‘小张‘,

age:29

}

function Father(){

}

function Son(){

}

inherit(Son,Father);

var son = new Son();

console.log(son.name); //小张

//缺点:不能随便改变自己的原型,因为自己的原型和原来的函数用的是

//一个原型,自己的改,原来的相应的也会去改

var father = new Father();

Son.prototype.name = ‘小红‘;

console.log(son.name);  //小红

console.log(father.name);  //小红

(3) 代码图解:

  1. 圣杯模式(解决共享原型的不足)(用中间的构造函数解决)(最完美的继承模式)

(1)圣杯模式1

① 代码


//为了解决共享原型模式的不足,借用第三方函数,构建了圣杯模式

//封装

function inherit(Target,Origin){

function F(){}    //①

F.prototype = Origin.prototype; //②

Target.prototype = new F();  //③

}

//上面的代码中的②和③是不能调换位置的,因为这样的话Target会在继承Origin

//原型之前,从而先继承了F的原型

//应用

Father.prototype = {

name:‘小张‘,

age:29

}

function Father(){

}

function Son(){

}

inherit(Son,Father);

var son = new Son();

console.log(son.name); //小张

var father = new Father();

Son.prototype.name = ‘小红‘;

console.log(son.name);  //小红

console.log(father.name);  //小张

② 图解代码

(2) 圣杯模式2(因为圣杯模式1中继承关系,son的构造函数指向了Father,为了解决这一问题,推出了圣杯模式2)

① 说明son的构造函数为什么指向了Father

② 解决方法代码展示


//封装

function inherit(Target,Origin){

function F(){}    //①

F.prototype = Origin.prototype; //②

Target.prototype = new F();  //③

Target.prototype.constructor = Target;  //④  让Target.prototype指向的构造函数从Origin处转回到Target处

Target.prototype.uber = Origin.prototype; //⑤ 让构造出来的对象找到自己的超类(超级父级)(就是它最终继承于谁)

}

(3) 圣杯模式3(建议使用)(雅虎的工程师利用闭包的第三个特点:可以实现封装,属性私有化;推出了圣杯模式3)


var inherit = (function (){

var F = function (){};

return function(Target,Origin){

F.prototype = Origin.prototype;

Target.prototype = new F();

Target.prototype.constructor = Target;

Target.prototype.uber = Origin.prototype;

}

}())

  1. 闭包的第三个特点的应用(可以实现封装,属性私有化)

(1)代码展示


//可以实现封装,属性私有化

function Deng(name,wife){

var preperewife = ‘xiaozhang‘;

this.name = name;

this.wife = wife;

this.divorce = function(){      //①

this.wife = preperewife; // 这个对象里面的属性为什么可以用外部的变量呢

},

this.changePreparewife = function(target){  //②

preperewife = target;

},

this.sayPreparewife = function(){ //③

console.log(preperewife);

}

}

var deng = new Deng(‘deng‘,‘xiaoliu‘);

//①②③函数和Deng函数形成了闭包

(2)代码说明


//deng中只保存了Deng函数中的那个this对象,因为最后有个return this,形成闭包后,把这个

//preperewife这个属性拿走了,形成了自己的私有化变量

//为什么通过deng.preperewife访问属性时,返回undefined,因为this对象上根本没有这个属性

//只是this上的①②③方法通过AO拿到了这个变量(preperewife),所以通过this上相应的方法可以

//访问到它,这个preperewife就好比自己的私人变量,从表面上直接是访问不到的


//而雅虎工程师正是利用了闭包的这一特点,对圣杯模式进行了改进,才成为了下面的圣杯模式

// var inherit = (function (){

//     var F = function (){};

//     return function(Target,Origin){

//         F.prototype = Origin.prototype;

//         Target.prototype = new F();

//         Target.prototype.constructor = Target;

//         Target.prototype.uber = Origin.prototype;

//     }

// }())

(二) 命名空间

  1. 概念:管理变量,防止污染全局,适用于模块化开发
  2. 在企业开发中,每个人会负责某一项目上的某一功能,最后把这些功能合并在一起这样肯定会在一个html文件中引入多个js文件,这样的话,每个js文件中可能有

变量名的冲突,出现变量名覆盖的现象,从而想出了命名空间

  1. 代码说明

//在企业开发中,每个人会负责某一项目上的某一功能,最后把这些功能合并在一起

//这样肯定会在一个html文件中引入多个js文件,这样的话,每个js文件中可能有

//变量名的冲突,出现变量名覆盖的现象,从而想出了命名空间

var obj = {

department1:{

zhangsan:{

name:‘xiaolizi‘

},

lisi:{

name:‘xiaowangba‘

}

},

department2:{

wangmazi:{

name:‘xiaokeai‘

}

}

}

//调用

obj.department1.zhangsan.name;

//但是这样写太麻烦,可以改进一下

var zhangsan =  obj.department1.zhangsan;

zhangsan.name;

//但是命名空间现在因为各种工具的出现(如:webpack)已经被弃用了

//虽然命名空间这种方法已经不用了,但是我们依然可以在不使用工具的情况下

//解决上面的问题

  1. 上面所说的在不使用工具的情况下解决问题的方法就是利用闭包的第四个特点
  2. 闭包的第四个特点的应用(模块化开发,防止污染全局变量)

(1) 代码展示与说明


//虽然命名空间这种方法已经不用了,但是我们依然可以在不使用工具的情况下

//解决上面的问题

//这种方法就是闭包+立即执行函数,这也正是闭包的第四点应用:模块化开发,

//防止污染全局变量

var name = ‘bcd‘;

var init = (function(){

var name = ‘abc‘;

function callName(){

console.log(name);

}

return function(){

callName();

}

}())

init();

  1. init是初始化的意思,企业开发时,我们经常把入口函数用init命名
  2. 原生js模拟jquery链式调用

//在一个对象里面,this指向第一人称,即这个对象

var deng = {

smoke : function() {

console.Log(‘ Smoking,... xuan cool!!!‘);

return this;

},

drink: function () {

console.log(‘drinking..., ye cool!‘);

return this;

},

perm: function () {

console.Log(‘ preming.... cool!‘);

return this;

}

}

deng.smoke().drink().perm().smoke().drink();

  1. 在一个对象里面,this指向第一人称,即这个对象
  2. 属性的表示方法

(1)obj.prop

(2)obj[‘prop’](这个比较灵活,建议使用这个)

(3)obj.prop  ——>  obj[‘prop’](这是隐式转换过程)

(4)属性名的拼接必须使用中括号

(5)代码展示


var deng = {

wife1: { name: "xiaoliu" },

wife2: { name: "xiaozhang" },

wife3: { name: "xiaomeng" },

wife4: { name: "xiaowang" },

sayWife: function (num) {

return this[‘wife‘ + num];

}

}

//  隐式转换

//obj.属性名  ————————————>  obj[‘属性名‘]

(一) 对象的枚举

  1. 对象中属性是字符串形式的
  2. for in 循环

(1) 在开发中,对象中的length我们是无从知道的,对象中放的什么我们也不知道,但是我们现在想知道里面有什么,就必须用到for in循环

(2) for in 循环的主要目的就是遍历对象,它是通过对象中属性的个数来控制循环圈数的

(3) 代码展示与说明


// var obj = {

//     name:‘xiaolizi‘,

//     age:23,

//     sex:‘男‘

// }

// for( var i in obj ){

//     console.log(obj.i);  //undefined

// }

//为什么会打印出undefined,因为

//obj.i ————>  obj[‘i‘]  ————>  它认为这个i是一个字符串(属性)

//解决方案

var obj = {

name:‘xiaolizi‘,

age:23,

sex:‘男‘

}

for( var i in obj ){

console.log(obj[i]);

}

  1. hasOwnProperty

(1) 因为for in循环会把我们自己手动给原型上添加的属性,打印出来

这是我们不需要的,因此我们需要hasOwnProperty进行过滤

(2) 代码展示与说明


//hasOwnProperty 可以判断这个属性属于原型还是属于自己

var obj = {

name:‘xiaolizi‘,

age:23,

sex:‘男‘,

__proto__:{

lastName:‘zhang‘

}

}

for( var i in obj ){

if( obj.hasOwnProperty(i) ){//判断是i(自己)的属性还是原型上的属性

console.log(obj[i]);

}

}

(3) for in循环会打印自己手动设置的原型方法和属性,但是不会打印系统设定好的方法和属性

  1. in 操作符

(1) ‘属性名’ in 对象 (该属性属不属于这个对象)(true/false)

(2) in无法分别这个属性是属于对象自己的还是原型的

  1. instanceof

(1) A instanceof B

① A对象是不是B构造函数构造出来的对象(官方)

② 看A对象的原型链上有没有B的原型

(2) {}.constructor 不能这样写,因为可能把{}识别为函数体

  1. 区别一个变量是数组还是对象的方法

(1) 通过构造器 变量.constructor

(2) 通过instanceof  变量 instanceof  Array

(3) toString() (推荐)(因为前两个在父子域问题上有一点差错)

① 各个构造函数都修改了toString()

② Object.prototype.toString.call(变量)

③ Object.prototype.toString = function() {}

④ 谁调用toString(),this就指向谁,③的式子中this指向终极原型

⑤ 用call可以改变this的指向,从而让this指向②中的这个变量

原文地址:https://www.cnblogs.com/080-hll/p/12506218.html

时间: 2024-10-14 18:46:19

继承模式,命名空间,对象枚举的相关文章

命名空间 对象枚举

//命名空间 //利用闭包防止变量污染 1 var name = 'bcd'; 2 var init = (function () { 3 var name = 'abc'; 4 function callName() { 5 console.log(name) 6 } 7 return function () { 8 callName(); 9 } 10 }()); 11 init(); 12 var li = { 13 wife1 : {name:"l"}, 14 wife2 :

js继承模式、命名空间、对象枚举

继承模式 继承发展史 1.传统形式--原型链 过多的继承了没用的属性 2.借用构造函数 不能继承借用构造函数的原型 每次构造函数要多走一个函数 3.共享原型 不能添加自己原型的自定义属性,会把共享原型的对象的原型的属性也更改. 4.圣杯模式 //1.原型链 Grand.prototype.lastName = "li"; function Grand(){ } var grand = new Grand(); Father.prototype = grand; function Fat

面向对象为什么要多用对象模式而少用继承模式?

进来学习java的时候遇到了一些经验说多用对象模式,少用继承模式.现在写一点感想. 面向对象的对象之间的哦和方式有继承,实现,关联,依赖,聚合和组合.其中的继承和实现是继承这类模式. 说道的一个原因就是代码污染.例如一个父类非常复杂.而一个继承了这个类的子类可能重写了一部分的方法.但是继承了全部的方法.用户在使用继承的子类的时候可能会调用没有重写的父类的方法并且如果这种方法是在子类的设计者的意图之外的操作,那么子类在继承父类的时候,可以认为不光是继承到了有用的功能,还继承到了垃圾功能,父类的代码

3. 闭包_对象组合继承模式_事件轮询机制

1.谈谈闭包? (产生条件.是什么.在哪里.作用.生命周期.缺点) 产生闭包的三个条件: 函数嵌套 内部函数引用外部函数的局部变量 执行外部函数 包含被引用的局部变量的一个"对象",  通过 chrome 开发者工具可以调试查看到,就是 closure,它存在嵌套的内部函数中 作用: 延长了局部变量的存活时间, 让函数外部可以操作(读写)到函数内部的数据(变量/函数) 闭包的生命周期: 产生 :  在嵌套内部函数定义执行完时就产生了(不是在调用) 死亡 :  在嵌套的内部函数成为垃圾对

对象冒充实现继承,原型链继承方法,以及组合继承模式

function Person (){ this.name=“张三”; this.run = function(){ alert( this.name+'在运动' ) } } Person.prototype.work = function(){ alert( this.name+'在工作’ ) } // web类 继承person类 原型链+对象冒充的组合继承模式 function web(){ Person.call( this )  //  对象冒充实现继承 } var w = new w

ES5继承模式

果然,感觉有些东西不整理一下还是很容易忘记的,很多时候有需要不断地去复习,感觉JavaScript这门语言总体上不能算是特别难,但是知识点特别杂(坑也特别多...),感觉最好还是能够梳理出一个整体架构出来 好了,废话不多说,今天大致上总结一下ES5中的继承模式,大致上还是参照<JavaScript高级程序设计>上来的. 原型模式 function Person (name, age) { this.name = name; this.age = age; } ? Person.prototyp

js继承模式

组合继承是js常用的继承模式,指的是将原型链和借用构造函数的技术结合在一起.其中的思想是使用原型链实现原型属性和方法的继承, 而通过借用构造函数实现对属性的继承. 例子: <script> function SuperType(name){ this.name = name; this.colors = ["red","blue"]; } SuperType.prototype.sayName = function(){ alert(this.name)

9、Cocos2dx 3.0游戏开发找小三之工厂方法模式与对象传值

重开发者的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27704153 工厂方法模式 工厂方法是程序设计中一个经典的设计模式,指的是基类中只定义创建对象的接口,将实际的实现推迟到子类中. 在这里,我们将它稍加推广,泛指一切生成并返回一个对象的静态函数. 一个经典的工厂方法如同这样: Sprite* factoryMethod() { Sprite* ret = new Sprite(); //在这里对 ret

面向对象--多继承&amp;派生类对象内存布局分析&amp;各基类指针所指向的位置分析

背景 原文链接:ordeder  http://blog.csdn.net/ordeder/article/details/25477363 关于非虚函数的成员函数的调用机制,可以参考: http://blog.csdn.net/yuanyirui/article/details/4594805 成员函数的调用涉及到面向对象语言的反射机制. 虚函数表机制可以查看下面这个blog: http://blog.csdn.net/haoel/article/details/1948051 总结为: 其一