您的位置:首页 > Web前端 > JavaScript

js加强:原型,创建对象分析,继承

2017-01-21 14:50 816 查看

1.原型 (重点,难点)

讲师:觉月

概念:

Function、Object:Js自带的函数对象。

prototype:每一个函数对象都有一个显示的prototype属性,它代表了对象的原型(Function.prototype函数对象是个例外,没有prototype属性)。

__proto__:每个对象都有一个名为__proto__的内部隐藏属性,指向于它所对应的原型对象(chrome、firefox中名称为__proto__,并且可以被访问到)。原型链正是基于__proto__才得以形成(note:不是基于函数对象的属性prototype)。

 

原型的意义 :

1.构造函数的原型上的属性和方法可以被所有的实例所共享  ,利用JS来创造各种对象时,将所有的实例方法放在构造函数的原型中

2.如果扩展JS本身的一些API的时候,可以将扩展的方法放在JS内置对象的原型中

 


1原型prototype

prototype是构造函数的一个属性, 该属性指向一个对象. 而这个对象将作为该构造函数所创建的所有实例的基引用(basereference), 可以把对象的基引用想像成一个自动创建的隐藏属性. 当访问对象的一个属性时, 首先查找对象本身, 找到则返回; 若不, 则查找基引用指向的对象的属性(如果还找不到实际上还会沿着原型链向上查找,  直至到根). 只要没有被覆盖的话, 对象原型的属性就能在所有的实例中找到.原型默认为Object的新实例, 由于仍是对象, 故可以给该对象添加新的属性:



__proto__

 

虽然每个函数都有原型.但是我们一般讨论的是构造函数的原型,因为如果将一个函数当做普通函数来调用的话,函数调用完毕之后,函数本身占用过的系统资源将会被回收,普通函数的原型对象没有使用过,研究没有意义.   只有构造函数的原型有意义,因为构造函数创建的每一个实例都有一个隐藏的__proto__属性,指向了构造函数的原型.

 

 

原型模式执行流程

当实例中的属性和方法和原型中的属性和方法重名的时候,我们通过实例去访问重名属性和方法的时候, 优先访问实例中的属性和方法.

 

原型被重写

原先系统为构造函数分配的原型将不复存在.我们通过构造函数或者构造创建出来的引用访问原型中的属性和方法,是后来的原型中的方法和属性.

 

 

如何判断属性是在构造函数的实例里,还是在原型里?

  实例.hasOwnProperty(“属性名”); //实例里有返回true.

in:操作符: 能够通过对象访问给定属性时返回true,否则返回false,无论这个属性

   是存在于实例中还是原型中.  alert(‘name’ in  stu);

如何判断原型中是否存在属性?

   function isProperty(object, property){

      return !object.hasOwnProperty(property)&&(propertyin object);

   }

 

原型:每个构造函数在分配空间的时候,系统自动的会给这个构造函数的内存上挂一个

   内存,这个内存叫做构造函数的原型.

意义:我们通过构造函数实例化的各个对象可以访问到构造函数中原型中的属性和方法.

 

 

区分概念: 每个函数都有原型.但是我们关注的是构造函数的原型.   如果是普通函数的话,

  函数执行完毕,以后再也不调用这个函数,GC(垃圾回收)会在某个不确定的时间将其回收.

__proto__ :每个实例都有__proto__这个属性,它指向了创造这个实例的构造函数的原型

constructor:每个原型都有constructor属性,它指向原型所在的构造函数

 

原型链:




 

 

 

function Stu(){}//var Stu=new Function();  Function这个构造函数也有原型

var s=new Stu();

 

alert(i);

作用域链:当我们在代码中的人和一个区域访问一个变量i的时候,首先在当前作用域寻找

   有没有一个变量i,如果有拿过来在直接使用即可.如果没有,去当前作用域的上层作用域

  去寻找有没有变量i如果有拿过来在直接使用即可.如果没有,在去上层作用域的上层去寻 

  找,依次类推,一直寻找到全局域,如果找不到报错 i is notdefined.

 

alert(s.name);

  原型链

  当我们访问一个对象的属性的时候s.name的时候,首先访问实例本身中是否存在一个属性name,如果有拿过来直接使用即可,如果没有,去创造这个实例的构造函数的原型中去寻找是否存在一个属性name,如果有拿过来直接使用即可,如果没有,去创造构造函数的原型的构造函数的原型中去寻找,依次类推,一直找到object对象的原型,如果没有,报错.

 

 

 

利用原型扩展api

<script>

/**

*字符串-去掉前后空白字符

*/

String.prototype.trim = function(){

       return this.replace(/(^\s*)|(\s*$)/g, "");

}

/**

*字符串-去掉前空白字符

*/

String.prototype.ltrim = function(){

       return this.replace(/(^\s*)/g, "");

}

/**

*字符串-去掉后空白字符

*/

String.prototype.rtrim = function(){

       return this.replace(/(\s*$)/g, "");

}

      

      

var str=new String(" abc ");

alert("@"+str+"@");

var str2=str.trim();

alert("@"+str2+"@");

 

 

// 原型的意义 : 1.构造函数的原型上的属性和方法可以被所有的实例所共享  ,利用JS来创造各种对象时,将所有的实例方法放在构造

//      函数的原型中

//     2.如果扩展JS本身的一些API的时候,可以将扩展的方法放在JS内置对象的原型中

 

//跨域:

</script>

 

 

2.创建对象深入分析

java创建对象内存分析



js创建对象内存分析



js运行内存分析



js创建对象方式:

 

1.字面量方式 var o={};   var o=new Object();

<script>

var obj1={};//  <===>var obj3=new Object();

obj1.name="lucy";

obj1.fn=function(){}

 

 

 

var obj2={"name":"tom","age":19}; //json格式的对象

//string   {"name":"tom","age":19}   xml

 

 

function Stu(name,age){

         this.name=name;

         this.age=age;

         this.fn=function(){alert("fn.....");}

}

var s=new Stu("tom",18);

//alert(s.name+"  "+s.age);

//alert(s['name']+"  "+s['age']);   //

//s["fn"]();

 

delete s.name;  //实例上的name属性删除

alert(s.name);

 

 

 /*

  * 1. 可以通过数组的形式来访问对象的属性/方法

  * 2. 我们认为 var o={}  var o={name:tom,age:19}   var o=new Object(); o.name="tom"; o.age=20;

  *    都是同一种创建对象的方式. 因为都是在object之上绑定属性和方法

  *    优点:前后台传递数据的时候很方便

  *    缺点:大量创建同种对象的时候,代码量大

  */

</script>

 

2.工厂模式

<script>

function createStu(name,age){

         var o=new Object();

         o.name=name;

         o.age=age;

         o.fn=function(){alert("fn.....")}

         return o;

}

function createPerson(name,age,sex){

         var o=new Object();

         o.name=name;

         o.age=age;

         o.sex=sex;

         o.fn=function(){alert("fn.....")}

         return o;

}

 

 

var s1=createStu("tom",19);

var s2=createStu("mary",20);

var p1=createPerson("mary",20,"帅哥");

 

alert(s1.name);

alert(s2.name);

 

/*

 * 优点:相对于第1种创建对象的方式 var o={}; o.name="tom"; o.age=19; o.fn=function(){}

 *     节省代码

 * 缺点:无法正确的识别通过工厂模式创造的各种实例的类型  

 */

</script>

 

3.构造模式

<script>

function Stu(name,age){

         this.name=name;

         this.age=age;

         this.fn=function(){alert("fn.....")}

}

 

function Person(name,age){

         this.name=name;

         this.age=age;

         this.fn=function(){alert("fn.....")}

}

var s=new Stu("tom",18);

 

var p=new Person("tom",18);

alsert(s instanceof Stu);  //true

alsert(p instanceof Person);//true

 

 

/*

 * 优点:代码量少,可以正确的区分各种实例所属的类型

 * 缺点:占用内存

 */

</script>

 

4.原型方式

<script>

function Stu(name,age){

         this.name=name;

         this.age=age;

}

Stu.prototype.fn=function(){alert("fn....."+this.name+" "+this.age)}

 

 var s1=new Stu("tom",18);

 var s2=new Stu("mary",19);

 alert(s1.fn==s2.fn); //true

 

/*

 * 优点:性能问题得到了彻底的解决

 * 缺点:结构不是一个整体

 */

</script>

 

5.构造函数+原型模式

6.动态原型模式

<script>

function Stu(name,age){

         this.name=name;

         this.age=age;

        

        

         if(Stu.prototype.fn=='undefined'){

                  Stu.prototype.fn=function(){alert("fn....."+this.name+" "+this.age)}         

         }

}

 

 var s1=new Stu("tom",18);

 var s2=new Stu("mary",19);

 alert(s1.fn==s2.fn); //true

</script>

 

 

7. JS中的this

   本质上还和Java中的this一样,代表当前对象.

 

创建对象内存分析对比(java,js)

Java

js

3.内建对象

  内建对象大致可以分为三组  JavaScript本身提供出来供我使用的对象.

1.数据封装类对象 ObjectArray Boolean Number String .这些对象代表着JavaScript中

  的不同的数据类型.并且都拥有各自不同的typeof返回值,以及undefined和null状态

2.工具类对象: Math,Date,RegExp等对象

 3.错误类对象,包括一般性错误对象以及其他各种更特殊的错误类对象,它们可以在

   某些异常发生时帮助我们纠正程序工作状态.

常用内置对象:

String对象:处理所有的字符串操作

Math对象:处理所有的数学运算

Date对象:处理日期和时间的存储、转化和表达

Array对象:提供一个数组的模型、存储大量有序的数据

Event对象:提供JavaScript事件的各种处理信息

 

内置对象都有自己的方法和属性,访问的方法如下:

   对象名.属性名称

   对象名.方法名称(参数表)

               

4.继承

 1.  回顾继承的特点,有什么优点?

class Person{name,age,salary ; calSala(){}}

class 保安{ ……}

    class 收银{ ……}

class 促销{ ……}

优点:

1.减少代码量

 2.设计方面讲,各个类的层次更清晰了.更接近与人类的理解方式.

世界是什么样子,软件就是什么样子的.

人类的分析思路:

电商: 物物交换   业务: 用户角度:

 

抽取 DRY: don’trepeat you self

 

2.  继承的实现5种方式

     * 对象冒充

<script>

  function Parent(username){

    this.username = username;

    this.hello = function(){

      alert(this.username);

    }

  }

 

  function Child(username,password){

    //通过以下3行实现将Parent的属性和方法追加到Child中,从而实现继承

    //第一步:this.method是作为一个临时的属性,并且指向Parent所指向的对象,

    //第二步:执行this.method方法,即执行Parent所指向的对象函数

    //第三步:销毁this.method属性,即此时Child就已经拥有了Parent的所有属性和方法

    this.method = Parent;

    this.method(username);//最关键的一行

         delete this.method;

 

    //window.Parent(username);  errror

 

    this.password = password;

    this.world = function(){

      alert(this.password);

    }

  }

  var child = new Child("lisi","123456");

  child.world();

  //alert(window.username);

  child.hello();

</script>

 

     * call()方法调用

<script>

         var s1,s2;

  function Parent(username){

       s1=this;

    this.username = username;

    this.hello = function(){

      alert(this.username);

    }

  }

   

  function Child(username,password){

    Parent.call(this,username);

         s2=this;

    this.password = password;

    this.world = function(){

      alert(this.password);

    }

  }

  var child = new Child("lisi","123456");

  child.world();

 

  child.hello();

 

alert(s1==s2);

alert(s1==child);

alert(s2==child);

</script>

 

     * apply()方式调用

<script>

  function Parent(username){

    this.username = username;

    this.hello = function(){

      alert(this.username);

    }

  }

 

  function Child(username,password){

    Parent.apply(this,[username]);

    this.password = password;

    this.world = function(){

      alert(this.password);

    }

  }

  var child = new Child("lisi","123456");

  child.world();

 

  child.hello();

 

</script>

 

     * 原型链方式

<script>

  function Person(){

  }

  Person.prototype.hello = "hello";

  Person.prototype.sayHello = function(){

    alert(this.hello);

  }

 

 

  function Child(){

  }

  //var s=new Person();

  //Child.prototype = s;

//这行的作用是:将Parent中将所有通过prototype追加的属性和方法都追

//加到Child,从而实现了继承

  Child.prototype = new Person();

  Child.prototype.world = "world";

  Child.prototype.sayWorld = function(){

    alert(this.world);

  }

 

  var c = new Child();

  

  c.sayWorld();

  c.sayHello();

</script>

 



 

 

 

以后再开发中如果碰到其他形式的继承:

  始终遵循的原则: 1.重写原型.如果重写了原型,在向原型中存放成员,那么我们访问到的

原型中的成员,是重写之后的那块区域,系统原先默认提供的原型区域不存在

 2.原型链的原则.

 

 

 

     * 混合方式

<script>

    function Person(name,age){

                  this.name=name;

                  this.age=age;

         }

         Person.prototype.self=function(){

                  alert(this.name+this.age);

         }

        

         function Stu(name,age,sex){

                  Person.call(this,name,age);

                  this.sex=sex;

         }

         Stu.prototype=new Person();

         Stu.prototype.saySex=function(){alert(this.sex);}

        

         var s1=new Stu("tom",18,"女生");

         s1.self();

         s1.saySex();

         /*

          * 1.父类 的设计: 对象属性还是放在父类的实例属性中  对象的方法放置在父类的原型中

          * 2.在子类中的第一句话 通过函数的call调用继承父类的成员

          * 3.子类中新增加的属性还是当做实例属性来处理

          * 4.重写子类的原型对象,原型是父类的一个实例

          * 5.子类中新增加的方法放在子类的原型中

          */

</script>

 

5. 构建自己的JS类库

DRY dno’t repeat youself

 

1.什么是JS库 

   将常用的一些方法封装起来,放在一个JS文件中让大家调用

 functionaddEvent(dom,type,fn){

 }

2.编写自己的JS库需要注意什么

   减少全局变量和最外层函数.

   如果团队开发JS代码,我们需要访问每个人的JS代码.实现命名空间,类似Java中的包

 

实现命名空间样例:

<script src="myUtil1.js"></script>

<script src="myUtil2.js"></script>

<script>

         function fn(){

                  ZhangSan.fn();

                  ZhangSan.tool.msg("ZZZ");

                  LiSi.fn();

         }

         fn();

</script>

 

myUtil1.js

(function(){

       window["ZhangSan"]={}; //<====>window.ZhangSan=new Object();

       function fn(){

                //打印那个函数在调用当期函数

                alert(arguments.callee.caller);

       }

      

       function Tool(){

                this.msg=function(msg){

                         document.write(msg);

                }

               

       }

       window["ZhangSan"]["fn"]=fn;

       window["ZhangSan"]["tool"]=new Tool();

})();

 

 

myUtil2.js

(function(){

       window["LiSi"]={}; //<====>window.ZhangSan=new Object();

       function fn(){

                //打印那个函数在调用当期函数

                alert("我是李四的fn...");

       }

       window["LiSi"]["fn"]=fn;

})();

 

4.模拟JQuery

 

myJquery.js

(function() {

         var jQuery = function(selector) {

                  return jQuery.fn.init(selector);

         }

        

         jQuery.fn = jQuery.prototype = {

                          init: function(selector) {

                                   if (typeof selector == "string") {

                                                     this[0] = document.getElementById(selector);

                                                     return this;

                                   }

                          },

                          html: function() {

                                   if (arguments.length == 0) {

                                                     return this[0].innerHTML;

                                   }

                                   else {

                                            this[0].innerHTML = arguments[0];

                                   }

                          },

                          version: "8.8.8"

         }

         jQuery.fn.init.prototype = jQuery.fn;

         window.$ = window.jQuery = jQuery;

})();

 

1. JQuery内部就仅仅包装了一个对象jQuery,同时jQuery还是一个函数,$是jQuery别名

 

 jQuery.post();

 

 

 

 

案例:创建js日志对象

思维的提升:

 

 

 

www.w3cshool.cc  菜鸟

www.51cto.com

www.csdn.com

www.cnblog.com

www.zuidaima.com  最代码

 

极客学院  慕课  51cto  IT行业

项目经理:svn/cvs/git 

 

 

外观:

文字:大小,间距,行高,缩进,字体,字的颜色

大小,定位,离左边和顶部的距离

背景:颜色,图片,图片的位置,图片的平铺方式

内外边距:  边框:粗细,样式,颜色

列表的样式

anli.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

<script src="myLog.js"></script>

<script>

       //前端工程: 前锋

       function fn(){

              var dm=document.getElementById("dv");

              myPackage.log.createWin();

              for(var i in dm){

                     //alert(i+"   "+dm[i]);

                     myPackage.log.writeMessage(i+"   "+dm[i]);

              }

             

              //myPackage.log.writeMessage("ZZZ1");

              //myPackage.log.writeMessage("ZZZ2");

                           

       }

</script>

</head>

<body>  

<div id="dv" title="ddd">AAAA</div>

<button onclick="fn()">按钮</button>

</body>

</html>

 

myLog.js

(function(){

      

       function MyLogger(){

         var logWin=null;

        

         this.createWin=function(){

                //alert("创建窗口");

                logWin=document.createElement("UL");

               

                logWin.style.height="350px";

                logWin.style.width="700px";

                logWin.style.border="1px solid red";

               

                var bdDom=document.getElementsByTagName("body")[0];

                bdDom.appendChild(logWin);

               

                logWin.style.position="absolute";

                logWin.style.left="150px";

                logWin.style.top="50px";

                logWin.style.padding="0px";

                logWin.style.overflow="scroll";

               

         }  

        

         this.writeMessage=function(msg){

                //alert("向窗口写入信息");

               

                var newDm=document.createElement("li");

                newDm.innerHTML=msg;

               

                newDm.style.borderBottom="1px solid green";

                newDm.style.listStyleType="none";

                newDm.style.margin="5px";

                logWin.appendChild(newDm);

         }  

       }

      

       window["myPackage"]={};

       window["myPackage"]["log"]=new MyLogger();

})()

 

 

 

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: