轉載地址http://blog.csdn.net/lmj623565791/article/details/34089553
javascript
今css
天重溫了下Javacript,給你們帶來一篇Javascript博文,相信對於Javacript有必定了解的人都聽過prototype原型這個概念,今天咱們深度的分析下prototype與__proto__。html
好了,下面看一個很是簡單的例子:html5
- var Person = function(name)
- {
- this.name = name ;
- };
- var p = new Person("Ben");
- console.log(p.name);
代碼簡單的 你不用說明了,若是如今讓你們根據上面的代碼畫一張包含Function與Object的內存圖,你們確定回想什麼叫包含Function與Object,上面的代碼和它們有幾毛錢的關係。好了,下面我先按要求把圖畫出來,你們參考下:
![](http://static.javashuo.com/static/loading.gif)
解析下:java
一、任何一個由構造器產生的對象都有__proto__屬性,且此屬性指向該構造器的prototype。jquery
二、全部構造器/函數的__proto__都指向Function的prototypeandroid
拿第2條對比第1條,貌似咱們發現了什麼,沒錯函數的構造器就是Function,看下面的代碼:web
-
- var Person = function(name)
- {
- this.name = name ;
- };
-
- function Person(name)
- {
- this.name = name ;
- }
-
- var Person = new Function("name" , "this.name = name ;" );
固然了不能說說,下面看代碼驗證:
- console.log(Person.__proto__ === Function.prototype);
- console.log(typeof p.__proto__);
- console.log(p.__proto__.__proto__ === Object.prototype);
有人會問,那麼Function與Object的prototype,__prop__究竟是什麼呢?
- console.log(Object.__proto__ === Function.prototype);
- console.log(Function.__proto__ === Function.prototype);
- console.log(Function.prototype.__proto__ == Object.prototype);
- console.log(Object.prototype.__proto__);
有此可見ajax
一、全部的構造器包括Object和Function都繼承了Function.prototype的方法,由第三行可知全部的構造器都是對象,即js中一切皆爲對象。編程
二、__proto__最終的指向都是Object.prototype,這也就是js中的原型鏈。
最後咱們看一下Object的文檔:
The following table lists properties of the Object Object.
發現Object還有個constructor屬性。
一、constructor屬性指向的是建立當前對象的構造函數。
二、每一個函數都有一個默認的屬性prototype,而這個prototype的constructor默認指向這個函數
看下面的例子:
-
- var Person = function(name)
- {
- this.name = name ;
- };
-
- var p = new Person("Ben");
-
- console.log(p.constructor === Person);
- console.log(Person.prototype.constructor === Person);
- console.log(Person.prototype instanceof Object);
- console.log(Person.prototype instanceof Person);
-
- Person.prototype = {name:"123"} ;
- var p2 = new Person("Ben");
- console.log(p2.constructor === Object);
- console.log(p2.constructor === Person.prototype.constructor);
- console.log(Person.prototype.constructor === Object);
- console.log(Person.prototype.constructor === Person);
當改變Person的prototype時,會發現,Person.prototype.constructor指向了Object,主要是由於:
Person.prototype = {name:"123"} 至關於Person.prototype=new Object({name:"123"} );此時的構造器變成了Object.
好了,就介紹到這裏,各位看官沒事留個言,贊一個,哈~。
轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/25076713
一直以爲Js很強大,因爲長期不寫js代碼,最近恰好溫故溫故。
一、Javascript沒有代碼塊做用域的概念,局部做用域是針對函數來講的。
二、若是不使用var聲明的變量,默認爲全局變量
三、Js中的做用域鏈
先看個簡單的例子:只有一個函數對象,函數對象和其它對象同樣,擁有能夠經過代碼訪問的屬性和一系列僅供JavaScript引擎訪問的內部屬性。其中一個內部屬性是[[Scope]],由ECMA-262標準第三版定義,該內部屬性包含了函數被建立的做用域中對象的集合,這個集合被稱爲函數的做用域鏈,它決定了哪些數據能被函數訪問。
做用域鏈的圖:
![](http://static.javashuo.com/static/loading.gif)
注:圖中省略了,Global Scope中的window,document等,每一個函數對象中的arguments,this等均未畫出。
觀察上面代碼,存在fun03,f,g三個函數對象。
下面是做用域鏈的圖:
![](http://static.javashuo.com/static/loading.gif)
注:每一個函數對象一個做用域鏈,這裏直接畫在了一塊兒;對於變量的查找,先從鏈的0開始找。
函數對象 f 在代碼中執行了2 次,因此a*2*2 = 40 ; 函數對象 g 在代碼中執行了1次, 因此 a *2 = 20 ;
四、閉包
上面的例子能夠看到,在fun03執行完成後,a的實例並無被銷燬,這就是閉包。我的對閉包的理解是:函數執行完成後,函數中的變量沒有被銷燬,被它返回的子函數所引用。
下面以一個特別經典的例子,同時使用做用域鏈解析:
相信上面的代碼確定你們都寫過,本意是點擊每一個li,打印出它們的索引,但是事實上打印出的都是elements.length。這是爲何呢?
![](http://static.javashuo.com/static/loading.gif)
看下上面的簡易的做用域鏈(省略了不少部分,主要是理解),此時每一個onclick函數的i,指向的都是 onload 中的i 此時的 i = element.length.
下面看解決方案:
在onclick函數的外層,包了一層當即執行的函數,因此此時的n指向的 n 是當即執行的,全部都是1~elements.length 。
Javascript 進階 封裝
轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/25080573
js中到處是對象,面向對象的第一步固然就是封裝了,因爲Js中沒有類的概念,因此封裝起來也比較麻煩,下面介紹兩種js的封裝。
一、使用約定優先的原則,將全部的私有變量以_開頭
- <script type="text/javascript">
-
-
-
- var Person = function (no, name, age)
- {
- this.setNo(no);
- this.setName(name);
- this.setAge(age);
- }
- Person.prototype = {
- constructor: Person,
- checkNo: function (no)
- {
- if (!no.constructor == "string" || no.length != 4)
- throw new Error("學號必須爲4位");
- },
- setNo: function (no)
- {
- this.checkNo(no);
- this._no = no;
- }, getNo: function ()
- {
- return this._no;
- }, setName: function (name)
- {
- this._name = name;
- }, getName: function ()
- {
- return this._name;
- }, setAge: function (age)
- {
- this._age = age;
- }, getAge: function ()
- {
- return this._age;
- }, toString: function ()
- {
- return "no = " + this._no + " , name = " + this._name + " , age = " + this._age;
- }
- };
- var p1 = new Person("0001", "鴻洋", "22");
- console.log(p1.toString());
- p1.setNo("0003");
- console.log(p1.toString());
- p1.no = "0004";
- p1._no = "0004";
- console.log(p1.toString());
-
- </script>
看完代碼,是否是有種被坑的感受,僅僅把全部的變量以_開頭,其實仍是能夠直接訪問的,這能叫封裝麼,固然了,說了是約定優先嘛,這種方式仍是不錯的,最起碼成員變量的getter,setter方法都是prototype中,並不是存在對象中,整體來講仍是個不錯的選擇。若是你以爲,這不行,必須嚴格實現封裝,那麼看第二種方式。
二、嚴格實現封裝
看上面的代碼,去掉了this.屬性名,嚴格的實現了封裝,只能經過getter,setter訪問成員變量了,可是存在一個問題,全部的方法都存在對象中,增長了內存的開銷。
三、以閉包的方式封裝
- <script type="text/javascript">
-
-
-
-
- var Person = (function ()
- {
- var checkNo = function (no)
- {
- if (!no.constructor == "string" || no.length != 4)
- throw new Error("學號必須爲4位");
- };
-
- var times = 0;
-
- return function (no, name, age)
- {
- console.log(times++);
- var no , name , age;
- this.setNo = function (no)
- {
- checkNo(no);
- this._no = no;
- };
- this.getNo = function ()
- {
- return this._no;
- }
- this.setName = function (name)
- {
- this._name = name;
- }
-
- this.getName = function ()
- {
- return this._name;
- }
-
- this.setAge = function (age)
- {
- this._age = age;
- }
- this.
- getAge = function ()
- {
- return this._age;
- }
-
- this.setNo(no);
- this.setName(name);
- this.setAge(age);
- }
- })();
- Person.prototype = {
- constructor: Person,
- toString: function ()
- {
- return "no = " + this._no + " , name = " + this._name + " , age = " + this._age;
- }
- }
- ;
- var p1 = new Person("0001", "鴻洋", "22");
- var p2 = new Person("0002", "abc", "23");
- var p3 = new Person("0003", "aobama", "24");
-
-
- console.log(p1.toString());
- console.log(p2.toString());
- console.log(p3.toString());
-
- </script>
上述代碼,js引擎加載完後,會直接執行Student = 當即執行函數,而後此函數返回了一個子函數,這個子函數纔是new Student所調用的構造函數,又由於子函數中保持了對當即執行函數中checkNo(no) ,times的引用,(很明顯的閉包)因此對於checkNo和times,是全部Student對象所共有的,建立3個對象後,times分別爲0,1,2 。這種方式的好處是,可使Student中須要複用的方法和屬性作到私有且對象間共享。
一、基於類的繼承
下面看下面的代碼:
- <script type="text/javascript">
-
-
- function Person(name, age)
- {
- this.name = name;
- this.age = age;
- }
- Person.prototype.say = function ()
- {
- console.log(this.name + " , " + this.age);
- }
- function Student(no)
- {
- this.no = no;
- }
- <span style="white-space:pre">
-
- </span>
- Student.prototype = new Person();
- var stu1 = new Student("0001");
- stu1.name = '張三';
- stu1.age = '11';
- console.log(stu1.no);
- stu1.say();
-
-
- </script>
輸出結果:
能夠看到Student成功集成了Person,而且擁有了Person的say方法,核心代碼其實就是一句 Student.prototype = new Person();,下面經過圖解來講明原理:
![](http://static.javashuo.com/static/loading.gif)
將Student.prototype指向new Person() , new Person的_proto_又指向Person Prototype;這樣完成了整個繼承。
可是這種方式存在問題:
問題1:當父類存在引用類型變量時,形成數據不一致,下面咱們給Person添加一個hobbies屬性,類型爲數組。
- <script type="text/javascript">
-
-
-
-
-
-
-
- function Person(name, age)
- {
- this.name = name;
- this.age = age;
- this.hobbies = [] ;
- }
- Person.prototype.say = function ()
- {
- console.log(this.name + " , " + this.age +" , " +this.hobbies);
- }
- function Student(no)
- {
- this.no = no;
- }
- Student.prototype = new Person();
-
- var stu1 = new Student("0001");
- stu1.name = '張三';
- stu1.age = '11';
- stu1.hobbies.push("soccer");
- stu1.say();
-
- var stu2 = new Student("0002");
- stu2.name = '李四';
- stu2.age = '12';
- stu2.hobbies.push("girl");
- stu2.say();
-
- </script>
輸出結果:
- 張三 , 11 , soccer
- 李四 , 12 , soccer,girl
能夠看出,李四的hobbies應該只有girl,可是上面的代碼讓全部對象共享了hobbies屬性。
上述的繼承方式還存在一個問題:
問題2:在Student的構造方法中,沒法使用new Student("00001" , "張三" , 12) ;建立對象,並初始化name和age屬性,必須stu.name, stu.age進行賦值
爲了解決上述問題,對上述代碼進行修改:
- <script type="text/javascript">
-
- function Person(name, age)
- {
- this.name = name;
- this.age = age;
- this.hobbies = [];
- }
- Person.prototype.say = function ()
- {
- console.log(this.name + " , " + this.age +" , " + this.hobbies);
- }
-
- function Student(name, age, no)
- {
-
-
-
-
- Person.call(this, name, age);
- this.no = no;
- }
-
- Student.prototype = new Person();
-
- var stu1 = new Student("0001","張三",11);
- stu1.hobbies.push("soccer");
- stu1.say();
-
- var stu2 = new Student("0002","李四",12);
- stu2.hobbies.push("cangjin");
- stu2.hobbies.push("basketball");
- stu2.say();
-
- </script>
輸出:
- 0001 , 張三 , soccer
- 0002 , 李四 , cangjin,basketball
在Student的構造方法中使用了Person.call(this,name,age)感受就像super(name,age)【call的第一個參數爲上下文】;而且成功解決了對引用屬性的共享問題,完美解決。
二、基於原型鏈的繼承
- <script type="text/javascript">
-
-
-
-
-
-
- var Person = {
- name: "人",
- age: 0,
- hobbies: [],
- say: function ()
- {
- console.log(this.name + " , " + this.age + " , " + this.hobbies);
- }
- }
- ;
-
- var Student = clone(Person);
- Student.no ="";
- Student.sayHello = function()
- {
- console.log(this.name +"hello ") ;
- }
-
- var stu1 = clone(Student);
- stu1.name = "zhangsan";
- stu1.age = 12;
- stu1.hobbies.push("Java");
- stu1.say();
-
- var stu2 = clone(Student);
- stu2.name = "lisi";
- stu2.age = 13;
- stu2.hobbies.push("Javascript");
- stu2.say();
-
-
-
-
-
-
- function clone(obj)
- {
- var F = function ()
- {
- };
- F.prototype = obj;
- return new F();
-
- }
-
-
- </script>
輸出:
- zhangsan , 12 , Java
- lisi , 13 , Java,Javascript
能夠看出一樣存在引用屬性不一致的問題,而且整個操做所有基於對象,給人的感受不是很好,下面經過圖解解釋下原理:
![](http://static.javashuo.com/static/loading.gif)
對象間經過一個clone函數,不斷的返回一個新的對象,且prototype執行傳入的對象,整個繼承過程其實就是_proto_不斷的指向,造成一個鏈,因此叫作原型鏈。
好了,已經介紹完了,js的兩種集成的方式,最好使用的仍是經過類的繼承(上述第一種方案,解決存在問題的)。
若是代碼或者講解存在任何問題,歡迎留言指出。
Javascript的難點就是面向對象編程,上一篇介紹了Javascript的兩種繼承方式:Javascript 進階 繼承,這篇使用一個例子來展現js如何面向對象編程,以及如何基於類實現繼承。
一、利用面向對象的寫法,實現下面這個功能,實時更新數據的一個例子:
![](http://static.javashuo.com/static/loading.gif)
二、使用對上面類的繼承,完成下面的效果:
![](http://static.javashuo.com/static/loading.gif)
好了,很少說,js的訓練全靠敲,因此若是以爲面向對象不是很紮實,能夠照着敲一個,若是以爲很紮實了,提供了效果圖,能夠本身寫試試。
一、第一個效果圖代碼:
-
-
-
-
-
-
-
-
-
-
-
-
-
- function PlaceFieldEditor(id, value, parentEle)
- {
- this.id = id;
- this.value = value;
- this.parentEle = parentEle;
- this.initValue = value ;
-
- this.initElements();
- this.initEvents();
- }
-
- PlaceFieldEditor.prototype = {
- constructor: PlaceFieldEditor,
-
-
-
- initElements: function ()
- {
- this.txtEle = $("<span/>");
- this.txtEle.text(this.value);
-
- this.textEle = $("<input type='text' />");
- this.textEle.val(this.value);
-
- this.btnWapper = $("<div style='display: inline;'/>");
- this.saveBtn = $("<input type='button' value='保存'/>");
- this.cancelBtn = $("<input type='button' value='取消'/>");
- this.btnWapper.append(this.saveBtn).append(this.cancelBtn);
-
- this.parentEle.append(this.txtEle).append(this.textEle).append(this.btnWapper);
-
- this.convertToReadable();
- },
-
-
-
- initEvents: function ()
- {
- var that = this;
- this.txtEle.on("click", function (event)
- {
- that.convertToEditable();
- });
-
- this.cancelBtn.on("click", function (event)
- {
- that.cancel();
- });
-
- this.saveBtn.on("click", function (event)
- {
- that.save();
- });
-
- },
-
-
-
- convertToEditable: function ()
- {
- this.txtEle.hide();
- this.textEle.show();
- this.textEle.focus();
-
- if(this.getValue() == this.initValue )
- {
- this.textEle.val("");
- }
-
- this.btnWapper.show();
- },
-
-
-
- save: function ()
- {
- this.setValue(this.textEle.val());
- this.txtEle.html(this.getValue().replace(/\n/g,"<br/>"));
-
- var url = "id=" + this.id + "&value=" + this.value;
-
- console.log(url);
- this.convertToReadable();
- },
-
-
-
- cancel: function ()
- {
- this.textEle.val(this.getValue());
- this.convertToReadable();
- },
-
-
-
- convertToReadable: function ()
- {
- this.txtEle.show();
- this.textEle.hide();
- this.btnWapper.hide();
- },
- setValue: function (value)
- {
- this.value = value;
- },
- getValue: function ()
- {
- return this.value;
- }
- }
- ;
引入到頁面代碼:
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <title></title>
- <script type="text/javascript" src="jquery-1.8.3.js"></script>
- <script type="text/javascript" src="PlaceFieldEditor.js"></script>
-
- <script type="text/javascript">
- $(function ()
- {
-
- $("ul li").each(function ()
- {
- new PlaceFieldEditor($(this).attr("id"), "請輸出成績...", $(this));
- });
-
-
- });
-
- </script>
-
- <style type="text/css">
- body
- {
- font-size: 12px;
- color: #333;;
- }
-
- ul li
- {
- line-height: 30px;
- }
-
- </style>
- </head>
- <body>
-
-
- <ul>
- <li id="1">張三:</li>
- <li id="2">李四:</li>
- <li id="3">王二:</li>
- </ul>
-
- </body>
- </html>
嗯,代碼就不詳細說了,都比較簡單,使用了jQuery,若是不喜歡可使用原生js,本人比較喜歡把jQuery看成js的工具使用。
二、第二個效果圖的js代碼:
-
-
-
-
-
-
-
- function PlaceAreaEditor(id, value, parentEle)
- {
- PlaceAreaEditor.superClass.constructor.call(this, id, value, parentEle);
- }
-
- extend(PlaceAreaEditor, PlaceFieldEditor);
-
- PlaceAreaEditor.prototype.initElements = function ()
- {
- this.txtEle = $("<span/>");
- this.txtEle.text(this.value);
-
- this.textEle = $("<textarea style='width:315px;height:70px;' />");
- this.textEle.text(this.value);
-
- this.btnWapper = $("<div style='display: block;'/>");
- this.saveBtn = $("<input type='button' value='保存'/>");
- this.cancelBtn = $("<input type='button' value='取消'/>");
- this.btnWapper.append(this.saveBtn).append(this.cancelBtn);
-
- this.parentEle.append(this.txtEle).append(this.textEle).append(this.btnWapper);
-
- this.convertToReadable();
-
- };
寫了PlaceAreaEditor繼承了PlaceFieldEditor,而後複寫了initElements方法,改變了text爲textarea。
extend的方法,上一篇博客已經介紹過:
-
-
-
-
- function extend(subClass, superClass)
- {
- var F = function ()
- {
- };
- F.prototype = superClass.prototype;
-
- subClass.prototype = new F();
-
- subClass.superClass = superClass.prototype;
- }
最後頁面代碼:
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <title></title>
- <script type="text/javascript" src="jquery-1.8.3.js"></script>
- <script type="text/javascript" src="PlaceFieldEditor.js"></script>
- <script type="text/javascript" src="com.zhy.extend.utils.js"></script>
- <script type="text/javascript" src="PlaceAreaEditor.js"></script>
-
- <script type="text/javascript">
-
- $(function ()
- {
- $("ul li div").each(function ()
- {
- new PlaceAreaEditor($(this).attr("id"), "請留言...", $(this));
- });
- });
-
- </script>
-
- <style type="text/css">
-
- body
- {
- font-size: 12px;
- color: #333;;
- }
-
- ul li
- {
- padding: 5px 0 8px 0 ;
- }
-
- </style>
- </head>
- <body>
-
-
- <ul>
- <li id="1"><h3>我要改劇本,不讓~~</h3>
- <div>
- </div>
- </li>
-
- <li id="2"><h3>懸崖上有橋麼,有?沒有~ </h3>
- <div>
- </div>
- </li>
- <li id="3"><h3>你敢打壞個人燈?不租~ </h3>
- <div>
- </div>
- </li>
- </ul>
-
- </body>
- </html>
好了,結束~~ 上面的例子是根據孔浩老師的例子修改的,感謝孔浩老師,孔老師地址:
www.konghao.org。
孔老師錄製了不少Java相關視頻,有興趣的能夠去他網站學習!
代碼或者講解有任何問題,歡迎留言指出。
轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/30490955
一直很喜歡Js,,,今天寫一個Js的單例模式實現以及用法。
一、單例模式的寫法
單例模式寫法至關簡單:
- var singleTon = {
- m1: "memeber first ",
- m2: "memeber second ",
- f1: function ()
- {
- console.log("fun1 ");
- }
- };
好了,結束了,其實就是字面量建立對象的方式,很簡單吧。若是你以爲單例太簡單,不用看了,那你就錯了,單例在Js中用的地方挺多,話說你常常用麼~。
二、單例用法一:建立命名空間
在開發中一個頁面通常會引入多個Js文件,甚至這多個文件多人寫的,你們均可能在全局定義init這個方法,均可能在全局聲明name這是屬性。這樣的話就形成的命名的衝突,發生一些意想不到的問題。因此咱們須要引入命名空間:
咱們可讓每一個程序猿寫的Js在他本身的命名空間下:
-
-
-
-
- var ZhangHongYang = {};
-
- var zhy = {};
- zhy.com = {} ;
- zhy.com.js = {};
好比以每一個人的名字做爲命名空間,以後寫方法就:ZhangHongyang.xxx();或者你習慣了Java的命名空間,也能夠zhy.com.js.xxx。
三、單例實例:實現一個註冊頁面的Js
針對像註冊頁面上的Js,通常都是針對此頁面寫的,建議使用單例的方式書寫。
下面的展現如何使用單例的寫法,實現ajax的註冊功能,固然沒有服務器,模擬一下:
html:
- <body>
- <form action="user/register" id="registerForm">
-
- <div>
- <label for="username">username</label>
- <input type="text" name="username" id="username"/>
- </div>
- <div>
- <label for="nickname">nickname</label>
- <input type="text" name="nickname" id="nickname"/>
- </div>
- <div>
- <label for="password">password</label>
- <input type="text" name="password" id="password"/>
- </div>
-
- <div>
- <input type="submit" value="Register"/>
- </div>
- </form>
-
- <div id="registerResult" style="width: 400px;height: 200px;border: 1px solid #444;">
-
- </div>
-
-
- </body>
當用戶點擊submit,會進行一些列的處理,最終將數據展現到registerResult中:
- <script type="text/javascript">
-
-
-
-
-
-
-
-
-
-
-
-
-
- ZhangHongYang.singlePageJsForRegister =
- {
- ID_FROM: "registerForm",
- ID_RESULT_CONTAINER: "registerResult",
- init: function ()
- {
- ZhangHongYang.singlePageJsForRegister.form = $("#" + this.ID_FROM);
- ZhangHongYang.singlePageJsForRegister.result = $("#" + ZhangHongYang.singlePageJsForRegister.ID_RESULT_CONTAINER);
- this.form.submit(this.handleSubmit);
- },
- handleSubmit: function (event)
- {
-
- var datas = {};
- ZhangHongYang.singlePageJsForRegister.form.find("input").each(function (i)
- {
-
- if (!($(this).attr("type") == "button" || $(this).attr("type") == "submit" || $(this).attr("type") == "reset" ))
- {
- datas[$(this).attr("name")] = $(this).val();
- }
- });
- ZhangHongYang.singlePageJsForRegister.ajaxSubmit(datas);
-
- event.preventDefault();
- },
- ajaxSubmit: function (datas)
- {
- var url = ZhangHongYang.singlePageJsForRegister.form.attr("action");
- console.log("url :" + url);
-
-
-
- ZhangHongYang.singlePageJsForRegister.showResult(datas);
- },
- showResult: function (datas)
- {
- var result = "";
- for (var p in datas)
- {
- result += p + " = " + datas[p] + "<br/>";
- }
- ZhangHongYang.singlePageJsForRegister.result.html(result);
- }
- };
-
- $(function ()
- {
- ZhangHongYang.singlePageJsForRegister.init();
- });
-
-
- </script>
咱們使用單例定義了一個singlePageJsForRegister方法對象,而後將須要用到的元素的Id做爲了常量,而後經過init初始化事件等,還有其餘的幾個函數,代碼中也書寫了註釋。看了上面的代碼可能以爲這麼寫好複雜,代碼量也多了,可是對於Js的提高,要慢慢的學習面向對象以及結構化的寫法,不能在script標籤中,不斷的定義各類方法,甚至在html標籤中書寫onclick這類的屬性。Js必定要保證,html與js文件解耦;js代碼總體上結構清晰;學習使用面向對象的方式處理問題。
![](http://static.javashuo.com/static/loading.gif)
四、如何在單例建立的對象中,定義私有方法和屬性
上述單例的寫法,會把全部的方法與變量暴露給使用者, 如何設置私有變量或者私有方法。
a、採用約定的方式:全部以_開頭的方法和變量都是私有變量。
-
-
-
-
- var singleTon = {
- _m1: "hello",
- _f1: function ()
- {
- },
- init: function ()
- {
- }
- };
能夠以爲方式1不是本身騙本身麼,可是項目嘛,約定因爲配置,也是可行的。實在以爲不能忍受,看方式二:
-
-
-
- var singleTon = (function ()
- {
- var _m1 = "hello";
- var _f1 = function ()
- {
- console.log(" i am a private function !");
- }
-
- return {
-
- init: function ()
- {
-
- _f1();
- }
- };
-
- })();
採用了閉包的方式,很好的實現了私有變量和私有方法的隱藏。
五、單例實例:解決Textarea的數據存儲時的Html轉Txt和展現時Txt轉Html
在web項目中,不少狀況會使用到Textarea。
a、好比留言、技能的書寫等;對於這類Textarea咱們有必要對用戶輸入的html代碼作特殊處理,防止用戶填寫惡意代碼或者把頁面的樣式弄亂。
b、相反來講,在Textarea中書寫的換行以及空格,最終在div中顯示卻沒有效果,都是一個空格,全部不少web開發者會選擇使用只讀textarea來回顯用戶輸入內容,其實須要作必定的轉換。
html:
- <body>
- <textarea style="width: 400px;height: 120px;" id="taContent">
- </textarea>
-
- <input type="button" id="convert" value="Convert"/>
- <br/>
- <br/>
-
-
- <fieldset style="width: 400px">
- <legend>html轉化爲Txt,供Div展現</legend>
- <div style="width: 400px;height: 120px;border: 1px solid #555;" id="divContent">
-
- </div>
- </fieldset>
-
- <br/>
- <br/>
-
- <fieldset style="width: 400px">
- <legend>Txt轉化爲Html,供Textarea修改</legend>
- <textarea style="width: 400px;height: 120px;" id="taEdit">
- </textarea>
- </fieldset>
-
- </body>
第一個Textarea用於用戶輸入,而後通過轉義顯示到div中,而後將轉義後的數據進行逆向恢復顯示到第二個TextArea中。至關與模擬了,div中展現數據和用戶再次編輯數據,這些功能在項目中都至關實用。
咱們的js代碼:
-
-
-
- ZhangHongYang.htmlFilter = (function ()
- {
-
-
-
-
-
- function _transSpace(data)
- {
- return data.replace(/\n/g, "<br/>").replace(/\s/g, " ");
- };
-
-
-
-
-
- function _transBrace(data)
- {
- return data.replace(/</g, "<").replace(/>/g, ">");
- };
-
-
- function _resumeSpace(data)
- {
- return data.replace(/ /g, " ").replace(/<br\s*\/>/ig, "\n");
- };
- function _resumeBrace(data)
- {
- return data.replace(/</g, "<").replace(/>/g, ">");
- };
-
- return {
-
- txt2Html: function (data)
- {
- return _transSpace(_transBrace(data));
-
- }, html2Txt: function (data)
- {
- return _resumeSpace(_resumeBrace(data));
- }
- };
-
- })();
在個人命名空間下定義了htmlFilter方法,而後最後暴露兩個方法Html2Txt和Txt2Html給使用者。
調用的代碼:
- <script type="text/javascript">
- $(function ()
- {
- $("#convert").click(function ()
- {
- var txt = ZhangHongYang.htmlFilter.txt2Html($("#taContent").val());
- console.log(txt);
- $("#divContent").html(txt);
- $("#taEdit").val(ZhangHongYang.htmlFilter.html2Txt(txt));
- });
- });
- </script>
效果圖:
![](http://static.javashuo.com/static/loading.gif)
能夠看到換行、空格、以及惡意的HTML代碼等都獲得了很好的在DIV中的顯示;且最終可還原爲Textarea中供編輯;若是各位項目中沒有考慮到這類問題,首先你能夠測試下問題,而後可使用上面的代碼解決這類問題。
六、單例寫法提升多分支代碼效率
相信你們都瞭解過ajax,對象ajax確定離不開XMLHttpRequest,並且不一樣版本、類型的瀏覽器建立方式不一致。通常咱們可能會這麼寫建立XMLHttpRequest的方法:
- function createXhr()
- {
- var xmlhttp;
- if (window.XMLHttpRequest)
- {
- xmlhttp=new XMLHttpRequest();
- }
- else
- {
- xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
- }
-
- return xmlhttp ;
- }
存在一個問題,每次建立XHR對象都須要進行分支判斷,若是某個方法分支特別多,咱們能夠作進一步的優化,當瀏覽器加載js文件時,就決定之後調用只會用其中合適的方式,而不會走分支。
咱們把代碼改爲:
-
-
-
- ZhangHongYang.xhrFactroy = (function ()
- {
- function _ieCreateXhr()
- {
- return new ActiveXObject("Microsoft.XMLHTTP");
- }
-
- function _newCreateXhr()
- {
-
- return new XMLHttpRequest();
- }
-
- if (window.XMLHttpRequest)
- {
- return _newCreateXhr;
- }
- else
- {
- return _ieCreateXhr;
- }
- })();
當程序加載完成js文件後,會自動根據瀏覽器類型返回適合的方法,避免每次都會進行分支判斷,咱們只須要使用ZhangHongYang.xhrFactroy();建立XHR對象。
七、單例引入懶加載功能
上述的js的文件基本在引入頁面後,瀏覽器加載就會進行大量操做佔用內存,有時候咱們但願等到咱們去使用時再去執行一些操做,若是從未使用就省去沒必要要的內存消耗,咱們能夠進行以下改寫代碼:
-
-
-
- ZhangHongYang.xhrFactroy = (function ()
- {
- var _instance = null;
-
- function _constructor()
- {
- function _ieCreateXhr()
- {
- return new ActiveXObject("Microsoft.XMLHTTP");
- }
-
- function _newCreateXhr()
- {
-
- return new XMLHttpRequest();
- }
-
- if (window.XMLHttpRequest)
- {
- return _newCreateXhr;
- }
- else
- {
- return _ieCreateXhr;
- }
- }
-
- return {getInstance: function ()
- {
- if (_instance == null)
- {
- _instance = _constructor();
- }
- return _instance;
-
- }};
-
- })();
- <script type="text/javascript">
-
- var xhrFactoryMethod = ZhangHongYang.xhrFactroy.getInstance();
- console.log(xhrFactoryMethod());
-
- </script>
只有使用時纔會去執行_constructor()方法,而不是咱們以前的一加載完成就執行。
好了,js的單例模式已常常用的方法介紹完了,之後在書寫js代碼時,能夠嘗試使用上述的方法進行書寫,而不是大量定義全局function以及變量,請不要在html標籤中增長事件處理的代碼~
若是存在任何問題,或者有任何問題請留言~
HTML5 CSS3 誘人的實例 :模仿優酷視頻截圖功能
通常的視頻網站對於用戶上傳的視頻,在用戶上傳完成後,能夠對播放的視頻進行截圖,而後做爲視頻的展現圖。項目中也能夠引入這樣的功能給用戶一種不錯的體驗,而不是讓用戶額外上傳一張展現圖。
效果圖:
![](http://static.javashuo.com/static/loading.gif)
看起來仍是很不錯,下面我給你們分析下,極其核心代碼很簡單:
- _canvas = document.createElement("canvas");
- _ctx = _canvas.getContext("2d");
- _ctx.fillStyle = '#ffffff';
- _ctx.fillRect(0, 0, _videoWidth, _videoWidth);
- _ctx.drawImage(_video, 0, 0, _videoWidth, _videoHeight, 0, 0, _videoWidth, _videoHeight);
- var dataUrl = _canvas.toDataURL("image/png");
核心代碼就這幾行,利用了ctx.drawImage時,第一個參數能夠爲video對象,而後就是經過canvas拿到DataUrl,賦值給Img標籤了。關鍵點就這些。
下面來看整個例子:
HTML:
- <!DOCTYPE html>
- <html>
- <head>
- <title></title>
- <meta charset="utf-8">
-
- <style type="text/css">
-
-
- html
- {
- overflow: hidden;
- }
-
- body
- {
- background-color: #999;
- }
-
- video
- {
- display: block;
- margin: 60px auto 0;
- }
-
- #shotBar
- {
- position: absolute;
- bottom: 5px;
- height: 120px;
- width: 98%;
- background-color: #000;
- box-shadow: -5px -5px 10px #fff;
- border-radius: 5px;
- padding: 2px;
- overflow: auto;
- }
-
- #shotBar img
- {
- border: 3px solid #fff;
- border-radius: 5px;
- height: 110px;
- width: 210px;
- margin-left: 4px;
- }
-
-
- </style>
-
- <script type="text/javascript" src="../../../jquery-1.8.3.js"></script>
-
- <script type="text/javascript" src="videoshot.js"></script>
-
- <script type="text/javascript">
-
- $(function ()
- {
- ZhangHongyang.click2shot.init();
- });
-
- </script>
-
-
- </head>
- <body>
-
-
- <video src="media/style.mp4" controls id="video">
- </video>
- <div id="shotBar">
- </div>
- </body>
- </html>
html和css都是至關簡單的。
主要看Js的代碼:
-
-
-
-
-
-
-
-
- var ZhangHongyang = {};
- ZhangHongyang.click2shot = (function ()
- {
- var _ID_VIDEO = "video";
- var _ID_SHOTBAR = "shotBar";
- var _videoWidth = 0;
- var _videoHeight = 0;
- var _canvas = null;
- var _ctx = null;
- var _video = null;
-
- function _init()
- {
- _canvas = document.createElement("canvas");
- _ctx = _canvas.getContext("2d");
- _video = document.getElementById(_ID_VIDEO);
-
-
- _video.addEventListener("canplay", function ()
- {
- _canvas.width = _videoWidth = _video.videoWidth;
- _canvas.height = _videoHeight = _video.videoHeight;
- console.log(_videoWidth + " , " + _videoHeight);
- _ctx.fillStyle = '#ffffff';
- _ctx.fillRect(0, 0, _videoWidth, _videoWidth);
- $("#" + _ID_SHOTBAR).click(_click2shot);
-
- _video.removeEventListener("canplay", arguments.callee);
- });
-
- }
-
- function _click2shot(event)
- {
- _video.pause();
- _ctx.drawImage(_video, 0, 0, _videoWidth, _videoHeight, 0, 0, _videoWidth, _videoHeight);
- var dataUrl = _canvas.toDataURL("image/png");
-
-
- var $imgBig = $("<img/>");
-
- $imgBig.width(_videoWidth).height(_videoHeight).css({position: "absolute", left: _video.offsetLeft, top: _video.offsetTop, width: _videoWidth + "px", height: _videoWidth + "px"}).attr("src", dataUrl);
- $("body").append($imgBig);
-
-
- var $img = $("<img>");
- $img.attr("src", dataUrl);
- $(this).append($img);
-
- var offset = _getOffset($img[0]);
- $img.hide();
-
- $imgBig.animate({left: offset.x + "px", top: offset.y + "px", width: $img.width() + "px", height: $img.height() + "px"}, 200, function ()
- {
- $img.attr("src", dataUrl).show();
- $imgBig.remove();
- _video.play();
- });
-
-
- }
-
-
-
-
-
-
-
- function _getOffset(elem)
- {
- var pos = {x: elem.offsetLeft, y: elem.offsetTop};
- var offsetParent = elem.offsetParent;
- while (offsetParent)
- {
- pos.x += offsetParent.offsetLeft;
- pos.y += offsetParent.offsetTop;
- offsetParent = offsetParent.offsetParent;
- }
- return pos;
- }
-
-
- return {init: _init}
-
- })();
須要注意的是,video.canplay事件中獲取完屬性和一些操做後,必定要removeEventLinstener,不然暫停播放會一直調用此方法。點擊事件時,會暫停video,而後在video的位置生成一張圖片,使用jquery動畫移動到縮略圖的位置,而後移除文檔,縮略圖顯示,形成的動畫效果。
獲得圖片以後的上傳之類的操做,你們能夠本身添加。還有很重要的一點:canvas.toDataURL("image/png");可能須要在服務器中訪問才能正常使用,我把寫好的頁面拖到了tomcat中,你們能夠隨便啓動個什麼服務器,否則會報安全問題。
好了,若是這篇文章對你有幫助請頂一個,同時也歡迎你們留言~
轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/34089553
今天給你們帶來一個刮刮樂的小例子~基於HTML5 canvas的,有興趣的能夠改爲android版本的,或者其餘的~
效果圖:
![](http://static.javashuo.com/static/loading.gif)
貼一張我中500w的照片,咋辦啊,怎麼花呢~
![](http://static.javashuo.com/static/loading.gif)
好了,下面開始原理:
一、刮獎區域兩個Canvas,一個是front , 一個back ,front遮蓋住下面的canvas。
二、canvas默認填充了一個矩形,將下面canvas效果圖遮蓋,而後監聽mouse事件,根據mousemove的x,y座標,進行擦出front canvas上的矩形區域,而後顯示出下面的canvas的效果圖。
很簡單把~嘿嘿~
一、HTML文件內容:
- <!DOCTYPE html>
- <html>
- <head>
- <title></title>
- <meta charset="utf-8">
-
- <script type="text/javascript" src="../../jquery-1.8.3.js"></script>
- <script type="text/javascript" src="canvas2d.js"></script>
-
- <script type="text/javascript" src="GuaGuaLe2.js"></script>
-
- <script type="text/javascript">
-
- $(function ()
- {
- var guaguale = new GuaGuaLe("front", "back");
- guaguale.init({msg: "¥5000000.00"});
- });
- </script>
- <style type="text/css">
-
-
- body
- {
- background: url("s_bd.jpg") repeat 0 0;
- }
-
- .container
- {
- position: relative;
- width: 400px;
- height: 160px;
- margin: 100px auto 0;
- background: url(s_title.png) no-repeat 0 0;
- background-size: 100% 100%;
- }
-
- #front, #back
- {
- position: absolute;
- width: 200px;
- left: 50%;
- top: 100%;
- margin-left: -130px;
- height: 80px;
- border-radius: 5px;
- border: 1px solid #444;
- }
-
- </style>
-
- </head>
- <body>
-
- <div class="container"