转载地址http://blog.csdn.net/lmj623565791/article/details/34089553
今
天重温了下Javacript,给大家带来一篇Javascript博文,相信对于Javacript有一定了解的人都听过prototype原型这个概念,今天我们深度的分析下prototype与__proto__。
好了,下面看一个非常简单的例子:
var Person = function (name)
{
this .name = name ;
};
var p = new Person( "Ben" );
console.log(p.name);
代码简单的 你不用说明了,如果现在让大家根据上面的代码画一张包含Function与Object的内存图,大家肯定回想什么叫包含Function与Object,上面的代码和它们有几毛钱的关系。好了,下面我先按要求把图画出来,大家参考下:
解析下:
1、任何一个由构造器产生的对象都有__proto__属性,且此属性指向该构造器的prototype。
2、所有构造器/函数的__proto__都指向Function的prototype
拿第2条对比第1条,貌似我们发现了什么,没错函数的构造器就是Function,看下面的代码:
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__);
有此可见
1、所有的构造器包括Object和Function都继承了Function.prototype的方法,由第三行可知所有的构造器都是对象,即js中一切皆为对象。
2、__proto__最终的指向都是Object.prototype,这也就是js中的原型链。
最后我们看一下Object的文档:
The following table lists properties of the Object Object .
Property
Description
__proto__ Property
Specifies the prototype for an object.
constructor Property
Specifies the function that creates an object.
prototype Property
Returns a reference to the prototype for a class of objects.
发现Object还有个constructor属性。
1、constructor属性指向的是创建当前对象的构造函数。
2、每个函数都有一个默认的属性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.
好了,就介绍到这里,各位看官没事留个言,赞一个,哈~。
Javascript 进阶 作用域 作用域链 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/25076713
一直觉得Js很强大,由于长期不写js代码,最近刚好温故温故。
1、Javascript没有代码块作用域的概念,局部作用域是针对函数来说的。
function fun()
{
for ( var i = 0 ; i < 10 ; i++)
{}
console.log(i);
if ( true )
{
var b = "helloworld" ;
}
console.log(b);
}
fun();
2、如果不使用var声明的变量,默认为全局变量
function fun02()
{
a = "helloworld" ;
var b = "welcome" ;
}
fun02();
console.log(a);
console.log(b);
3、Js中的作用域链
先看个简单的例子:只有一个函数对象,函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。
var a = "hello" ;
function fun04()
{
a = "world" ;
var b = "welcome" ;
}
作用域链的图:
注:图中省略了,Global Scope中的window,document等,每个函数对象中的arguments,this等均未画出。
function fun03()
{
var a = 10;
return function (){
a*= 2 ;
return a ;
};
}
var f = fun03();
f();
var x = f();
console.log(x);
var g = fun03();
var y = g();
console.log(y);
观察上面代码,存在fun03,f,g三个函数对象。
下面是作用域链的图:
注:每个函数对象一个作用域链,这里直接画在了一起;对于变量的查找,先从链的0开始找。
函数对象 f 在代码中执行了2 次,所以a*2*2 = 40 ; 函数对象 g 在代码中执行了1次, 所以 a *2 = 20 ;
4、闭包
上面的例子可以看到,在fun03执行完成后,a的实例并没有被销毁,这就是闭包。个人对闭包的理解是:函数执行完成后,函数中的变量没有被销毁,被它返回的子函数所引用。
下面以一个特别经典的例子,同时使用作用域链解析:
window.onload = function ()
{
var elements = document.getElementsByTagName( "li" );
for ( var i = 0; i < elements.length ; i ++)
{
elements[i].onclick = function ()
{
alert(i);
}
}
}
相信上面的代码肯定大家都写过,本意是点击每个li,打印出它们的索引,可是事实上打印出的都是elements.length。这是为什么呢?
看下上面的简易的作用域链(省略了很多部分,主要是理解),此时每个onclick函数的i,指向的都是 onload 中的i 此时的 i = element.length.
下面看解决方案:
window.onload = function ()
{
var elements = document.getElementsByTagName( "li" );
for ( var i = 0; i < elements.length; i++)
{
(function (n)
{
elements[n].onclick = function ()
{
alert(n);
}
})(i);
}
}
在onclick函数的外层,包了一层立即执行的函数,所以此时的n指向的 n 是立即执行的,所有都是1~elements.length 。
Javascript 进阶 封装
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/25080573
js中处处是对象,面向对象的第一步当然就是封装了,由于Js中没有类的概念,所以封装起来也比较麻烦,下面介绍两种js的封装。
1、使用约定优先的原则,将所有的私有变量以_开头
看完代码,是不是有种被坑的感觉,仅仅把所有的变量以_开头,其实还是可以直接访问的,这能叫封装么,当然了,说了是约定优先嘛,这种方式还是不错的,最起码成员变量的getter,setter方法都是prototype中,并非存在对象中,总体来说还是个不错的选择。如果你觉得,这不行,必须严格实现封装,那么看第二种方式。
2、严格实现封装
看上面的代码,去掉了this.属性名,严格的实现了封装,只能通过getter,setter访问成员变量了,但是存在一个问题,所有的方法都存在对象中,增加了内存的开销。
3、以闭包的方式封装
上述代码,js引擎加载完后,会直接执行Student = 立即执行函数,然后此函数返回了一个子函数,这个子函数才是new Student所调用的构造函数,又因为子函数中保持了对立即执行函数中checkNo(no) ,times的引用,(很明显的闭包)所以对于checkNo和times,是所有Student对象所共有的,创建3个对象后,times分别为0,1,2 。这种方式的好处是,可以使Student中需要复用的方法和属性做到私有且对象间共享。
Javascript 进阶 继承
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/29194261
1、基于类的继承
下面看下面的代码:
输出结果:
可以看到Student成功集成了Person,并且拥有了Person的say方法,核心代码其实就是一句 Student.prototype = new Person();,下面通过图解来说明原理:
将Student.prototype指向new Person() , new Person的_proto_又指向Person Prototype;这样完成了整个继承。
但是这种方式存在问题:
问题1: 当父类存在引用类型变量时,造成数据不一致,下面我们给Person添加一个hobbies属性,类型为数组。
输出结果:
张三 , 11 , soccer
李四 , 12 , soccer,girl
可以看出,李四的hobbies应该只有girl,但是上面的代码让所有对象共享了hobbies属性。
上述的继承方式还存在一个问题:
问题2: 在Student的构造方法中,无法使用new Student("00001" , "张三" , 12) ;创建对象,并初始化name和age属性,必须stu.name, stu.age进行赋值
为了解决上述问题,对上述代码进行修改:
输出:
0001 , 张三 , soccer
0002 , 李四 , cangjin,basketball
在Student的构造方法中使用了Person.call(this,name,age)感觉就像super(name,age)【call的第一个参数为上下文】;并且成功解决了对引用属性的共享问题,完美解决。
2、基于原型链的继承
输出:
zhangsan , 12 , Java
lisi , 13 , Java,Javascript
可以看出同样存在引用属性不一致的问题,并且整个操作全部基于对象,给人的感觉不是很好,下面通过图解解释下原理:
对象间通过一个clone函数,不断的返回一个新的对象,且prototype执行传入的对象,整个继承过程其实就是_proto_不断的指向,形成一个链,所以叫做原型链。
好了,已经介绍完了,js的两种集成的方式,最好使用的还是通过类的继承(上述第一种方案,解决存在问题的)。
如果代码或者讲解存在任何问题,欢迎留言指出。
Javascript 进阶 面向对象编程 继承的一个例子
Javascript的难点就是面向对象编程,上一篇介绍了Javascript的两种继承方式:Javascript 进阶 继承 ,这篇使用一个例子来展示js如何面向对象编程,以及如何基于类实现继承。
1、利用面向对象的写法,实现下面这个功能,实时更新数据的一个例子:
2、使用对上面类的继承,完成下面的效果:
好了,不多说,js的训练全靠敲,所以如果觉得面向对象不是很扎实,可以照着敲一个,如果觉得很扎实了,提供了效果图,可以自己写试试。
1、第一个效果图代码:
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 = $( " " );
this .txtEle.text( this .value);
this .textEle = $( " " );
this .textEle.val( this .value);
this .btnWapper = $( "
" );
this .saveBtn = $( " " );
this .cancelBtn = $( " " );
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, " " ));
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;
}
}
;
引入到页面代码:
"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的工具使用。
2、第二个效果图的js代码:
写了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;
}
最后页面代码:
"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相关视频,有兴趣的可以去他网站学习!
代码或者讲解有任何问题,欢迎留言指出。
Javascript 设计模式 单例 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/30490955
一直很喜欢Js,,,今天写一个Js的单例模式实现以及用法。
1、单例模式的写法
单例模式写法相当简单:
var singleTon = {
m1: "memeber first " ,
m2: "memeber second " ,
f1: function ()
{
console.log("fun1 " );
}
};
好了,结束了,其实就是字面量创建对象的方式,很简单吧。如果你觉得单例太简单,不用看了,那你就错了,单例在Js中用的地方挺多,话说你经常用么~。
2、单例用法一:创建命名空间
在开发中一个页面一般会引入多个Js文件,甚至这多个文件多人写的,大家都可能在全局定义init这个方法,都可能在全局声明name这是属性。这样的话就造成的命名的冲突,发生一些意想不到的问题。所以我们需要引入命名空间:
我们可以让每个程序猿写的Js在他自己的命名空间下:
var ZhangHongYang = {};
var zhy = {};
zhy.com = {} ;
zhy.com.js = {};
比如以每个人的名字作为命名空间,之后写方法就:ZhangHongyang.xxx();或者你习惯了Java的命名空间,也可以zhy.com.js.xxx。
3、单例实例:实现一个注册页面的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中:
我们使用单例定义了一个singlePageJsForRegister方法对象,然后将需要用到的元素的Id作为了常量,然后通过init初始化事件等,还有其他的几个函数,代码中也书写了注释。看了上面的代码可能觉得这么写好复杂,代码量也多了,但是对于Js的提升,要慢慢的学习面向对象以及结构化的写法,不能在script标签中,不断的定义各种方法,甚至在html标签中书写onclick这类的属性。Js一定要保证,html与js文件解耦;js代码整体上结构清晰;学习使用面向对象的方式处理问题。
4、如何在单例创建的对象中,定义私有方法和属性
上述单例的写法,会把所有的方法与变量暴露给使用者, 如何设置私有变量或者私有方法。
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();
}
};
})();
采用了闭包的方式,很好的实现了私有变量和私有方法的隐藏。
5、单例实例:解决Textarea的数据存储时的Html转Txt和展示时Txt转Html
在web项目中,很多情况会使用到Textarea。
a、比如留言、技能的书写等;对于这类Textarea我们有必要对用户输入的html代码做特殊处理,防止用户填写恶意代码或者把页面的样式弄乱。
b、相反来说,在Textarea中书写的换行以及空格,最终在div中显示却没有效果,都是一个空格,所有很多web开发者会选择使用只读textarea来回显用户输入内容,其实需要做一定的转换。
html:
第一个Textarea用于用户输入,然后经过转义显示到div中,然后将转义后的数据进行逆向恢复显示到第二个TextArea中。相当与模拟了,div中展示数据和用户再次编辑数据,这些功能在项目中都相当实用。
我们的js代码:
ZhangHongYang.htmlFilter = (function ()
{
function _transSpace(data)
{
return data.replace(/\n/g, " " ).replace(/\s/g, " " );
};
function _transBrace(data)
{
return data.replace(/"<" ).replace(/>/g, ">" );
};
function _resumeSpace(data)
{
return data.replace(/ /g, " " ).replace(/ /ig, "\n" );
};
function _resumeBrace(data)
{
return data.replace(/"<" ).replace(/>/g, ">" );
};
return {
txt2Html: function (data)
{
return _transSpace(_transBrace(data));
}, html2Txt: function (data)
{
return _resumeSpace(_resumeBrace(data));
}
};
})();
在我的命名空间下定义了htmlFilter方法,然后最后暴露两个方法Html2Txt和Txt2Html给使用者。
调用的代码:
效果图:
可以看到换行、空格、以及恶意的HTML代码等都得到了很好的在DIV中的显示;且最终可还原为Textarea中供编辑;如果各位项目中没有考虑到这类问题,首先你可以测试下问题,然后可以使用上面的代码解决这类问题。
6、单例写法提高多分支代码效率
相信大家都了解过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对象。
7、单例引入懒加载功能
上述的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;
}};
})();
只有使用时才会去执行_constructor()方法,而不是我们之前的一加载完成就执行。
好了,js的单例模式已经常用的方法介绍完了,以后在书写js代码时,可以尝试使用上述的方法进行书写,而不是大量定义全局function以及变量,请不要在html标签中增加事件处理的代码~
如果存在任何问题,或者有任何问题请留言~
HTML5 CSS3 诱人的实例 :模仿优酷视频截图功能
一般的视频网站对于用户上传的视频,在用户上传完成后,可以对播放的视频进行截图,然后作为视频的展示图。项目中也可以引入这样的功能给用户一种不错的体验,而不是让用户额外上传一张展示图。
效果图:
看起来还是很不错,下面我给大家分析下,极其核心代码很简单:
_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:
>
< 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 >