web前端js开发常用的几个js效果

最近在中,为实现一个新功能弄的焦头烂额
的实现,在实现后写下些心得,供以后会跳入这坑的同志们参考。首先,当让是考虑使用范围,由于项目仅仅需要考虑在 WEBKIT 环境下使用,所以可以不用考虑 IE 这也使得代码少了很多的 if(){}else{} 判断。在 Mozilla 开发者网络 上发现 selection 和 range 这两个关于选区对象和光标对象,结合 Caret (一个用于判断当前光标位置的JS插件)后,一个大致的雏形就浮现出来。大概就长这样: 先整理思路,捋一捋实现步骤。大致思路如下:键入 @ 后将选择框显示出来将焦点定位在弹出框中的搜索框中点击选择框中的选项时,返回输入框输入框中显示 @xxx将光标定位在 @xxx 之后删除 @xxx 时需要整个 @xxx 一起删除由于项目使用了 angular 来构建,所以给的 demo 也是用 angular 来搭建的,但是不论用什么框架,想法有了,那么一切就好办了。主要涉及的几个方法:getSelection(window.getSelectio):获取光标所在的区域(一个div或是一个textarea);selection.getRangeAt:获取光标所在区域中光标选区的信息;range.setStart:设置光标选区的起始位置;range.setEnd:设置光标选区的结束位置;range.deleteContents:将光标选区选中的内容删除;range.insertNode:在光标选区中添加内容;selection.extend:将选区的焦点移动到一个特定的位置;selection.collapseToEnd:将当前的选区折叠到最末尾的一个点。html 结构&div class="demo-wrap" ng-controller="Controller"&
&!-- 文本输入框 --&
&div class="demo" id="demo" contenteditable="true" ng-keydown="keyIn($event)"&&/div&
&!-- 带有输入框的选人框 --&
&div class="select-person" id="selectPerson" ng-show="showSelect" ng-style="sPersonPosi"&
&input type="text" id="searchPersonInput" ng-model="personSearchText" ng-blur="missFocus()"&
&ul class="person-wrap"&
&li class="row" ng-click="sPersonDone({fullName:'所有人'})"&
&div class="col-1"&
&div class="img-wrap"&
&portrait src="" text="'所有'"&&/portrait&
&div class="col-2"&所有人&/div&
&li class="row" ng-click="sPersonDone(item)" ng-repeat="item in atList | filter :{fullName: personSearchText}"&
&div class="col-1"&
&div class="img-wrap"&
&portrait src="item.img" text="item.fullName.slice(-2)"&&/portrait&
&div class="col-2" ng-bind="item.fullName"&&/div&
&/div&&/div&样式相关的 CSS 代码就不放上来了,简要分析下页面结构,一个 contenteditable="true" 的输入框和一个 id="selectPerson" 的选人框。输入框使用 contenteditable="true" 主要是因为想在输入框中插入标签,将 @xxx 内容显示出不同的颜色(这就需要将 @xxx 放在一个标签中),绑定 keyIn 的键盘输入事件,用于检索用户输入 @ 和 backspace ,并做出相应的动作;选人框使用 showSelect 来控制是否显示,遍历显示需要显示的选人,以及使用 input 中的内容来过滤选人。实现 @ 选择相关代码如下:$scope.keyIn = function(e) {
var selection = getSelection();
var ele = $('#demo');
if (e.code == 'Digit2' && e.shiftKey) {
$scope.showSelect =
var offset = ele.caret('offset');
$scope.sPersonPosi = {
left: offset.left - 10 + 'px',
top: offset.top + 20 + 'px'
// 让选人框中的搜索框获取焦点
$('#searchPersonInput')[0].focus();
}}实现起来挺简单,代码也不复杂,利用 caret 插件获取到光标位置,将选人框在 @ 符号的下方显示出来,并同时实现了步骤中的第二步:将焦点放在搜索框中。选人实现主要涉及步骤为: 3、4、5 。当鼠标点击备选项时需要按顺序进行 3、4、5 步骤,所以需将 3、4、5 这 3 个步骤放在一起。相关代码如下:$scope.sPersonDone = function(person) {
// 成功选人后,关闭选择框,让输入框获取焦点。
$scope.showSelect =
var ele = $('#demo')[0];
ele.focus();
// 获取之前保留先来的信息。
// 需要修改 keyIn 的代码,保存选区以及光标信息,用于获取在光标焦点离开前,光标的位置
var selection = lastSelection.
var range = lastSelection.
var textNode = range.startC
// 删除 @ 符号。
range.setStart(textNode, range.endOffset);
range.setEnd(textNode, range.endOffset + 1);
range.deleteContents();
// 生成需要显示的内容,包括一个 span 和一个空格。
var spanNode1 = document.createElement('span');
var spanNode2 = document.createElement('span');
spanNode1.className = 'at-text';
spanNode1.innerHTML = '@' + person.fullN
spanNode2.innerHTML = ' ';
// 将生成内容打包放在 Fragment 中,并获取生成内容的最后一个节点,也就是空格。
var frag = document.createDocumentFragment(),
node, lastN
frag.appendChild(spanNode1);
while ((node = spanNode2.firstChild)) {
lastNode = frag.appendChild(node);
// 将 Fragment 中的内容放入 range 中,并将光标放在空格之后。
range.insertNode(frag);
selection.extend(lastNode, 1);
selection.collapseToEnd();};我们需要的效果是在 @ 选人后,将整理好的 @xxx 包装成一个标签,放在原先 @ 的位置,所以我们需要对原先的 $scope.keyIn 方法进行改造,保留原先的光标信息,方便在上面的方法中使用。改造后的 $scope.keyIn 方法如下:$scope.keyIn = function(e) {
var selection = getSelection();
var ele = $('#demo');
if (e.code == 'Digit2' && e.shiftKey) {
$scope.showSelect =
// 保存光标信息
lastSelection = {
range: selection.getRangeAt(0),
offset: selection.focusOffset,
selection: selection
$scope.showSelect =
// 设置弹出框位置
var offset = ele.caret('offset');
$scope.sPersonPosi = {
left: offset.left - 10 + 'px',
top: offset.top + 20 + 'px'
$('#searchPersonInput')[0].focus();
}}这里估计挺多人会有疑问,为啥要在生成的标签后面加一个空格,而且这个空格要通过 & 这样的方式实现。首先,先解释第一个问题:为啥要在标签后加一个空格?如果不加空格的话,之后在输入文字会添加在我们生成的标签中,也就是说如果不加空格来隔断我们生成的标签,我们在文本框里所做的操作就是在我们生成的标签中进行。而加了个空格就为了避免该问题的发生,使得文本编辑在正确的编辑框中进行。第二个问题:为啥不能直接加空格 ' ' ,而是通过 & ,不得不说这是个过个悲伤的事实,还是碰到了兼容性的问题,在 chrome 下运行好好的代码,在 node-webkit 中就会各种报错。原因在不断的 defug 后发现了: node-webkit 中,将一个 ' ' 添加到
contenteditable="true" 的 div 中会没有啊,坑爹啊有木有!!!呈上之前的代码来祭奠下。var spanNode1 = document.createElement('span');var node = document.createTextNode(' ');spanNode1.className = 'at-text';spanNode1.innerHTML = '@' + person.fullNvar frag = document.createDocumentFragment();frag.appendChild(spanNode1);frag.appendChild(node);range.insertNode(frag);selection.extend(node, 1);结果一上 node-webkit 环境各种报错。真是坑了个大爹。原因是光标定位不准,指定位置超出实际位置,但是 node-webkit 环境确实是可以输入空格的,一看原来是 & 而 & 不能通过 createTextNode 来创建,所以就有了之前的哪个曲线救国的策略了。删除实现终于捋到最后一个步骤了,删除时,需要将一整个标签一起删除。由于需要监听键盘的输入,所以就可与之前 keyIn 的代码写在一起。最终的 keyIn 代码为:$scope.keyIn = function(e) {
var selection = getSelection();
var ele = document.getElementById('demo');
if (e.code == 'Digit2' && e.shiftKey) {
// 保存光标信息
lastSelection = {
range: selection.getRangeAt(0),
offset: selection.focusOffset,
selection: selection
$scope.showSelect =
// 设置弹出框位置
var offset = $(ele).caret('offset');
$scope.sPersonPosi = {
left: offset.left + 'px',
top: offset.top + 30 + 'px'
$('#searchPersonInput')[0].focus();
} else if (e.code == 'Backspace') {
// 删除逻辑
// 1 :由于在创建时默认会在 @xxx 后添加一个空格,
// 所以当得知光标位于 @xxx 之后的一个第一个字符后并按下删除按钮时,
// 应该将光标前的 @xxx 给删除
// 2 :当光标位于 @xxx 中间时,按下删除按钮时应该将整个 @xxx 给删除。
var range = selection.getRangeAt(0);
var removeNode =
if (range.startOffset &= 1 && range.startContainer.parentElement.className != "at-text")
removeNode = range.startContainer.previousElementS
if (range.startContainer.parentElement.className == "at-text")
removeNode = range.startContainer.parentE
if (removeNode)
ele.removeChild(removeNode);
}};代码的逻辑都写在注释里了,这里就不多说了。这样就完成 @ 这一功能了。来源:SegmentFault
新浪微博中@功能的实现
实现该功能大致需要三步
第一步:定位输入框中的光标的top和left属性
IE中很容易实现。直接调用document...
一些常用的JS功能
一、判断用户名是否可用function Check(){var Name=document.myform.username.value.replace(/(^/s+|/s+$)/g,);//转换空格为...
web前端实现@提醒功能
web前端实现@提醒功能@xxx功能很多地方用到,比如微博、微信、qq这些通信的都有用到,那么这个功能是如何实现的?在开始实现功能前,先整理一下思路:输入@后将列表选择框显示出来点击选择框中的选项时,...
仿微信、QQ的@功能
仿微信、QQ的@功能
前言:前一段时间,公司有一个项目需要加入@功能,我当时也没有啥思路,然后去网上看看有没有前人写过类似的文章或者代码。然后我在这里http://download.csdn.ne...
有用过IM软件的,估计都有用过@功能,首先我们先理一下思路,想实现@功能需要什么功能:
在输入框中输入@,弹出一个页面给用户选择所需要@的用户
在选择所需要@的用户后,自动填充用户的名字到输入框中(扩...
1、实现页面刷新时滚动到指定高度
$(window).scrollTop(600); //600为高度,根据特殊情况随意修改...
TV20.&em&js&/em& (javascript的树形结构目录) 立即下载
上传者: Romy-L 时间: 2010...&em&40&/em&个直接可以拿来用的JavaScript实用&em&功能&/em&代码 3 积分 立即下载 ...
1.实现tab切换效果
这个功能是很久之前实现的,现在发上来,很长一段时间没更新博客了,真惭愧。这个JS代码还有很多修改的空间,先发上来,以后再发个更新的版本吧。
这是效果图:
第一种:选项卡单击点击切换
选项卡-点击触发效果
没有更多推荐了,DOM 选择器
javascript 代码
1234567回匹配到的第一个元素var&item&=&document.querySelector('.item');console.log(item);回匹配到的所有元素,是一个nodeList集合var&items&=&document.querySelectorAll('.item');console.log(items[0]);阻止默认行为javascript 代码124567891011121314151617生jsdocument.getElementById('btn').addEventListener('click',&function&(event)&{&&&&event&=&event&||&window.event;&&&&if&(event.preventDefault){&&&&&&&&法&阻止默认行为&&&&&&&&event.preventDefault();&&&&}&else{&&&&&&&&止默认行为&&&&&&&&event.returnValue&=&false;&&&&}},&false);$('#btn').on('click',&function&(event)&{&&&&event.preventDefault();});
javascript 代码
124567891011121314151617生jsdocument.getElementById('btn').addEventListener('click',&function&(event)&{&&&&event&=&event&||&window.event;&&&&if&(event.stopPropagation){&&&&&&&&法&阻止冒泡&&&&&&&&event.stopPropagation();&&&&}&else{&&&&&&&&止冒泡&&&&&&&&event.cancelBubble&=&true;&&&&}},&false);$('#btn').on('click',&function&(event)&{&&&&event.stopPropagation();});鼠标滚轮事件javascript 代码123456789101112$('#content').on(&mousewheel&DOMMouseScroll&,&function&(event)&{&&&&&&&&&var&delta&=&(event.originalEvent.wheelDelta&&&&(event.originalEvent.wheelDelta&&&0&?&1&:&-1))&||&(event.originalEvent.detail&&&&(event.originalEvent.detail&&&0&?&-1&:&1));&&&&&&&&&&if&(delta&&&0)&{&&&&&&&&&上滚动&&&&&&&&console.log('mousewheel&top');&&&&}&else&if&(delta&&&0)&{&&&&&&&&下滚动&&&&&&&&console.log('mousewheel&bottom');&&&&}&});
检测浏览器是否支持svg
javascript 代码
1234567function&isSupportSVG()&{&&&&&var&SVG_NS&=&'http://www.w3.org/2000/svg';&&&&return&!!document.createElementNS&&&!!document.createElementNS(SVG_NS,&'svg').createSVGRect;&}&试console.log(isSupportSVG());检测浏览器是否支持canvasjavascript 代码12345678910function&isSupportCanvas()&{&&&&if(document.createElement('canvas').getContext){&&&&&&&&return&true;&&&&}else{&&&&&&&&return&false;&&&&}}试,打开谷歌浏览器控制台查看结果console.log(isSupportCanvas());
检测是否是微信浏览器
javascript 代码
1234567891011function&isWeiXinClient()&{&&&&var&ua&=&navigator.userAgent.toLowerCase();&&&&&if&(ua.match(/MicroMessenger/i)==&micromessenger&)&{&&&&&&&&&return&true;&&&&&}&else&{&&&&&&&&&return&false;&&&&&}}试alert(isWeiXinClient());jQuery 获取鼠标在图片上的坐标javascript 代码1234567$('#myImage').click(function(event){&&&&取鼠标在图片上的坐标&&&&&console.log('X:'&+&event.offsetX+'\n&Y:'&+&event.offsetY);&&&&&&&&&取元素相对于页面的坐标&&&&&console.log('X:'+$(this).offset().left+'\n&Y:'+$(this).offset().top);});
验证码倒计时代码
1id=&send&type=&button&value=&发送验证码&javascript 代码效果预览12345678910111213141516171819生js版本var&times&=&60,&时设为60秒&&&&timer&=&null;&&&&&&&&&&&&document.getElementById('send').onclick&=&function&()&{&&&&时开始&&&&timer&=&setInterval(function&()&{&&&&&&&&times--;&&&&&&&&&&&&&&&&if&(times&&=&0)&{&&&&&&&&&&&&send.value&=&'发送验证码';&&&&&&&&&&&&clearInterval(timer);&&&&&&&&&&&&send.disabled&=&false;&&&&&&&&&&&&times&=&60;&&&&&&&&}&else&{&&&&&&&&&&&&send.value&=&times&+&'秒后重试';&&&&&&&&&&&&send.disabled&=&true;&&&&&&&&}&&&&},&1000);}
javascript 代码
12345678910111213141516171819202122本var&times&=&60,&&&&timer&=&null;$('#send').on('click',&function&()&{&&&&var&$this&=&$(this);&&&&&&&&时开始&&&&timer&=&setInterval(function&()&{&&&&&&&&times--;&&&&&&&&&&&&&&&&if&(times&&=&0)&{&&&&&&&&&&&&$this.val('发送验证码');&&&&&&&&&&&&clearInterval(timer);&&&&&&&&&&&&$this.attr('disabled',&false);&&&&&&&&&&&&times&=&60;&&&&&&&&}&else&{&&&&&&&&&&&&$this.val(times&+&'秒后重试');&&&&&&&&&&&&$this.attr('disabled',&true);&&&&&&&&}&&&&},&1000);});常用的一些正则表达式javascript 代码12345678910111213141516171819配字母、数字、中文字符&/^([A-Za-z0-9]|[\u4e00-\u9fa5])*$/&证邮箱&/^\w+@([0-9a-zA-Z]+[.])+[a-z]{2,4}$/&证手机号&/^1[3|5|8|7]\d{9}$/&证URL&/^http:\/\/.+\./证身份证号码&/(^\d{15}$)|(^\d{17}([0-9]|X|x)$)/&配中文字符的正则表达式&/[\u4e00-\u9fa5]/&配双字节字符(包括汉字在内)&/[^\x00-\xff]/
js时间戳、毫秒格式化
javascript 代码
1234567891011121314function&formatDate(now)&{&&&&&var&y&=&now.getFullYear();&&&&var&m&=&now.getMonth()&+&1;&意js里的月要加1&&&&&var&d&=&now.getDate();&&&&var&h&=&now.getHours();&&&&&var&m&=&now.getMinutes();&&&&&var&s&=&now.getSeconds();&&&&&&&&return&y&+&&-&&+&m&+&&-&&+&d&+&&&&&+&h&+&&:&&+&m&+&&:&&+&s;&}&var&nowDate&=&new&Date(4);alert(formatDate(nowDate));js限定字符数(注意:一个汉字算2个字符)html 代码id=&txt&type=&text&
javascript 代码
123456789101112131415161718符串截取function&getByteVal(val,&max)&{&&&&var&returnValue&=&'';&&&&var&byteValLen&=&0;&&&&for&(var&i&=&0;&i&&&val.length;&i++)&{&&&&&&&&if&(val[i].match(/[^\x00-\xff]/ig)&!=&null)&byteValLen&+=&2;&else&byteValLen&+=&1;&&&&&&&&if&(byteValLen&&&max)&break;&&&&&&&&returnValue&+=&val[i];&&&&}&&&&return&returnValue;}$('#txt').on('keyup',&function&()&{&&&&var&val&=&this.value;&&&&if&(val.replace(/[^\x00-\xff]/g,&&**&).length&&&14)&{&&&&&&&&this.value&=&getByteVal(val,&14);&&&&}});js判断是否移动端及浏览器内核javascript 代码1234567891011121314151618192021var&browser&=&{&&&&&versions:&function()&{&&&&&&&&&var&u&=&navigator.userAgent;&&&&&&&&&return&{&&&&&&&&&&&&&trident:&u.indexOf('Trident')&&&-1,&核&&&&&&&&&&&&&presto:&u.indexOf('Presto')&&&-1,&核&&&&&&&&&&&&&webKit:&u.indexOf('AppleWebKit')&&&-1,&果、谷歌内核&&&&&&&&&&&&&gecko:&u.indexOf('Firefox')&&&-1,&狐内核Gecko&&&&&&&&&&&&&mobile:&!!u.match(/AppleWebKit.*Mobile.*/),&否为移动终端&&&&&&&&&&&&&ios:&!!u.match(/\(i[^;]+;(&U;)?&CPU.+Mac&OS&X/),&&&&&&&&&&&&&android:&u.indexOf('Android')&&&-1&||&u.indexOf('Linux')&&&-1,&&&&&&&&&&&&&iPhone:&u.indexOf('iPhone')&&&-1&,&&&&&&&&&&&&&iPad:&u.indexOf('iPad')&&&-1,&&&&&&&&&&&&&webApp:&u.indexOf('Safari')&&&-1&&&&&&&&&};&&&&&}}&if&(browser.versions.mobile()&||&browser.versions.ios()&||&browser.versions.android()&||&browser.versions.iPhone()&||&browser.versions.iPad())&{&&&&&alert('移动端');&}
之前我用过一个检测客户端的库 觉得挺好用的,也推荐给大家 叫&device.js,大家可以
Googel 或 百度
GItHub仓库地址:
getBoundingClientRect()
获取元素位置
javascript 代码
123456返回一个对象,其中包含了left、right、top、bottom四个属性var&myDiv&=&document.getElementById('myDiv');var&x&=&myDiv.getBoundingClientRect().left;&var&y&=&myDiv.getBoundingClientRect().top;&当于jquery的:&$(this).offset().left、$(this).offset().top&//&js的:this.offsetLeft、this.offsetTopHTML5全屏javascript 代码12345678910111213function&fullscreen(element)&{&&&&if&(element.requestFullscreen)&{&&&&&&&&element.requestFullscreen();&&&&}&else&if&(element.mozRequestFullScreen)&{&&&&&&&&element.mozRequestFullScreen();&&&&}&else&if&(element.webkitRequestFullscreen)&{&&&&&&&&element.webkitRequestFullscreen();&&&&}&else&if&(element.msRequestFullscreen)&{&&&&&&&&element.msRequestFullscreen();&&&&}}fullscreen(document.documentElement);
CSS常见布局代码片段
首先我们来看看水平居中
1.margin + 定宽
width: 100
js/jquery/html前端开发常用到代码片段
js/jquery/html前端开发常用到代码片段
1.IE条件注释
条件注释简介
IE中的条件注释(Conditional comments)对IE的版本和IE...
前端开发中最常用的JS代码片段(二)
前端开发中最常用的JS代码片段(二)
一些前端开发中最常用的JS代码片段
HTML5 DOM 选择器
querySelector() 返回匹配到的第一个元素
item = document.querySelec...
分享一些前端开发中最常用的JS代码片段~ 干货~
HTML5 DOM 选择器// querySelector() 返回匹配到的第一个元素
var item = document.querySelector('.item');
console.log(...
开发中常用的一些JS代码片段
阻止默认行为// 原生js
document.getElementById('btn').addEventListener('click', function (event) {
100个常用的原生JavaScript函数
1、原生JavaScript实现字符串长度截取
复制代码代码如下:
function cutstr(str, len) {
var icou...
Array 数组
Array concatenation (数组拼接)
Array difference (数组比较)
Array includes (数组包含)
记得几年前刚工作那时,听到高大上的 JS闭包 一词 让我一头雾水,很多初学者也许和我当时一样困惑,其实 闭包 也并没那么高深莫测。
今天我写了篇简单的学习笔记 希望能帮助大家轻松理解 JS闭包。...
前端开发中最常用的JS代码片段
没有更多推荐了,web前端开发常用的几个js
一.table换行奇数和偶数行不同的颜色
二.input type=“text” 文本里面的默认字体颜色和获取焦点后的字体颜色变换
三.iframe 自适应调用页面的宽度和高度
实例1table换行奇数和偶数行不同的颜色
&script type="text/javascript"&
function load()
vartrs=document.getElementById("table1").getElementsByTagName("tr");
for(vari=0;i&trs.i++)
if(i%2==0)
trs[i].style.backgroundColor="#f7f7f7";
trs[i].style.backgroundColor="#ffffff";
在html页面里 初始化
&body onLoad="load()"&
注意table里的id
&table width="730" border="0"cellspacing="1" cellpadding="1"
id="table1"&
实例2 input type=“text” 文本里面的默认字体颜色和获取焦点后的字体颜色变换
var input_focus = function(t){
t.value = '';
t.style.color = '#676767';
var input_blur = function(t){
if(t.value==''){
t.value = '';
t.style.color ='#D0D0D0';
&input type="text" placeholder="默认字体" onfocus='input_focus(this)' onblur='input_blur(this)'/&
实例3 iframe 自适应调用页面的宽度和高度
调用iframe的页面
&iframesrc="text.html"
id="main" width="100%"height="100%" frameborder="0" scrolling="auto"&&/iframe&
备注:注意iframe里的id。
Text.html页面里的js
&scripttype="text/javascript"&
$(window.parent.document).find("#main").load(function(){
var main =$(window.parent.document).find("#main");
var thisheight = $(document).height()+50;
//+50看页面的高度加数值
main.height(thisheight);
从零开始,学习web前端之js特效
HTML5 DOM 选择器// querySelector() 返回匹配到的第一个元素
var item = document.querySelector('.item');
console.log(...
1.返回顶部
$(function(){
$('.top').hide();
$(window).scroll(function() {
在开发过程中经常用到总结出来的一些方法,收集整理,希望能给大家带来帮助,如有
错误,欢迎指正。
/*验证手机号码*/
function isTelNum(str){
var _tel = ...
前端:一切可视化的事物叫前端。
前端:包括了网页端和移动端。
网页端:HTML 4.0/CSS 2.0 /JS/JQuery 2.x/HTML 5.0/CSS 3.0/Boo...
没有更多推荐了,  首先,推荐一篇博客豪情的博客JS提高:
,里面的链接全是精华, 一般人我不告诉他;
  我们会先从JS的基本的设计模式开始,由浅入深, 会描述prototype,__proto__,consturctor等基础知识和JS的常见继承方式, 以及四个类工厂的推荐和使用(包括JS.Class,prototype的类工厂,john resig写的一个简洁类工厂库,以及Pjs一个很飘逸的继承库,很飘逸-_-),最后有3个参考资料链接:,最后有我个人的视频,欢迎拍砖哇, &///(o)_(o)////。
  工厂模式:因为使用用一个接口创建很多对象会产生大量的重复代码,为了解决这个问题,人们就开始使用工厂模式:
&!DOCTYPE html&
&title&&/title&
&meta charset="utf-8"&
//最好所有的代码自己打一遍, 增加印象;
function l ( arg ) {
console.log( arg );
//工厂模式:因为使用用一个接口创建很多对象会产生大量的重复代码,为了解决这个问题,人们就开始使用工厂模式:
function Person(hairs,face, eye) {
var o = new Object();
o.say = function(){
console.log("say someting to me!");
//我们通过 Person(0,1,2)就可以创建一个包含特定信息的Person对象, 以后要生成对象直接执行Person然后给他传参数就好了;
//比如我们要生成10个Person, 很方便很快;
var c = 10;
while( c-- ) {
console.log(Person(c,c,c))
  构造函数模式:使用构造函数模式我们能少些更多代码,比如上面的工厂模式我们可以改写成:&
&!DOCTYPE html&
&title&&/title&
&meta charset="utf-8"&
//最好所有的代码自己打一遍, 增加印象;
function l ( arg ) {
console.log( arg );
function Person(hairs, face, eye) {
this.hairs =
this.face =
this.eye =
//同样, 我们再生成10个小朋友
var c = 10;
while( c-- ) {
console.log( new Person(c,c,c) );
  //知识点1: 那么工厂模式和构造函数模式有什么区别呢:
  * 没有显式地创建对象
  * 直接把属性和方法赋值给了this
  * 没有return语句
  * 构造函数的前面有一个
  //&知识点2:
  * 通过new的构造函数会经过四个阶段:
  * 1:创建一个新对象;
  * 2:把this赋值给这个新对象
  * 3:执行构造函数中的代码
  * 4:返回新对象
  原型是神马?&原型就是公用的方法或者属性,这么理解最简单, 当然:
  & & 1、prototype本质上还是一个JavaScript对象;
&&&   2、每个函数都有一个默认的prototype属性;
&&&   3、通过prototype我们可以扩展Javascript的内建对象
  一些代码弄懂原型的本质:
&!DOCTYPE html&
&title&&/title&
&meta charset="utf-8"&
//最好所有的代码自己打一遍, 增加印象;
function l ( arg ) {
console.log( arg );
function Memo() {};
Memo.prototype.hehe = 1;
Memo.prototype.shut = function() {
console.log("miaomiao")
var m0 = new Memo();
var m1 = new Memo();
console.log(m0.shut === m1.shut); //ture, 因为m0的shut和m1的shut就是指向了Memo.prototype.shut这个方法,所以他们相等;
//Object.getPrototypeOf会返回实例的原型;
console.log(Object.getPrototypeOf(m0)) //输出了:Memo {hehe: 1, shut: function}
console.log( Memo.prototype.isPrototypeOf(m0) )// 输出:
//原型对象有一个很大的问题要非常注意 ==》》 原型的属性和方法是被共享的, 比如:
Memo.prototype.shut = "W_W";
l(m0.shut) //输出:W_W, 悲剧了吧, 本来原型上的shut是个方法, 被改成字符串以后, 实例上的shut也发生了改变;
l(m1.shut) //输出:W_W;
m0.__proto__.shut = 1111; //m0的__proto__指向了Memo.prototype.shut,__proto__在标准浏览器下面是不能枚举到的,但确实是存在的一个属性;
l(m1.shut) //输出了1111
//只要原型上的属性或者方法被改了, 实例上的也会发生改变;
&/body&&/html&
  知识点:Object.getPrototypeOf;
      Fn.prototype.isPrototypeOf( instance );
  好的, 现在再来了解一下constructor, 如果你已经知道constructor是什么的话, &这段略过,&constructor是默认指向创建当前对象的构造函数, 但是这里面有一些坑要注意, 比如你的原型prototype被改了, 实例的constructor就变了 ,
&!DOCTYPE html&
&title&&/title&
&meta charset="utf-8"&
//最好所有的代码自己打一遍, 增加印象;
function l ( arg ) {
console.log( arg );
var Fn = function(){
//我是构造函数Fn;
l("Fn的constructor");
l(Fn.prototype.constructor);
/*输出function (){
//我是构造函数Fn;
var f = new Fn;
l("f的constructor");
l(f.constructor);
* function (){
//我是构造函数Fn;
//当函数创建的时候默认就为prototype新建一个constructor指向自己;
l(Fn.constructor === Function); //输出true, Function这个构造函数是F
l(Fn.constructor) // 输出function Function() { [native code] } ,意思是Function这个构造函数 ;
l(Fn.constructor === Fn.__proto__.constructor) //输出 Fn的constructor实际上是指向Fn.__proto__的;
//好的, 现在重新定义一个Fn;
var Fn = function(){
//我是构造函数Fn;
Fn.prototype = {};
l(Fn.prototype.constructor)
/*打印出了内部的代码, 为什么呢? 因为我们改变了Fn的原型, Fn的constructor指向了{}空对象的C
* function Object() { [native code] }
  大家一定要懂的是实例上的__proto__就是指向原型上的prototype, 这样会少走一些弯路,可以节约更多的时间用来看片, 你懂的;  每一个函数新建的时候都有一个默认的prototype, &prototype这个对象上面默认有一个指向自己的  prototype和__proto__的区别:__proto__是实例和Person.prototype之间的关系,而constructor是实例和Person之间的关系
&!DOCTYPE html&
&title&&/title&
&meta charset="utf-8"&
//最好所有的代码自己打一遍, 增加印象;
function l ( arg ) {
console.log( arg );
var Fn = function() {};
Fn.prototype.hehe = 1;
Fn.prototype.lala = 2;
var f = new Fn;
l(f) //输出了Fn {hehe: 1, lala: 2} ;
l(f.__proto__) //输出了Fn {hehe: 1, lala: 2} ;
l(Fn.prototype === f.__proto__) //输出了true, 这里要懂的东西是实例上的__proto__这个属性指向了构造函数的
l(f === f.__proto__) //输出 这里要懂的是f是new出来的实例;
//因为f上面的hehe和lala都是继承的属性, 所以这里面的log并没有被输出;
for(var p in f){
l("输出所以属性:" + p); //输出所以属性:hehe demo.html:11;
输出所以属性:lala
//过滤非私有属性;
if( f.hasOwnProperty(p) )
l("输出私有属性" + p); //因为f没有私有属性,所以这边没有log出来;
  有了上面的基础, 我们开始说说JS的面向对象和继承吧;
  1:组合使用构造器和原型模式, 这种模式是构造函数和原型混合的模式, 使用最广泛, 认同度也最高的一种模式, 也是最基础的模式;
&!DOCTYPE html&
&title&&/title&
&meta charset="utf-8"&
//最好所有的代码自己打一遍, 增加印象;
function l ( arg ) {
console.log( arg );
function Duck( name ,word) {
this.name =
this.word =
Duck.prototype.say = function() {
console.log( this.name+" say : " + this.word )
var duck = new Duck("nono","hehe");
duck.say();
   寄生构造模式; 听名字真的很玄乎..其实跟工厂模式一模一样的, 其实就是自定义模型的封装;
&!DOCTYPE html&
&title&&/title&
&meta charset="utf-8"&
//最好所有的代码自己打一遍, 增加印象;
function l ( arg ) {
console.log( arg );
function Foxy(name , word) {
var result = new Object();
result.name =
result.word =
l( new Foxy("nono","say someting") ); //输出:Object {name: "nono", word: "say someting"} ;
function Monkey( ) {
var aResult = [];
//技巧:通过apply把arguments保存到数组;
aResult.push.apply(aResult, arguments);
l( new Monkey("nono","dino","kite","sam") );
//打印出了这个:["nono", "dino", "kite", "sam"];
//要注意的是使用寄生模式的返回的对象和构造函数一点关系都没有;
  JS的原型继承, 继承是依赖于原型链的;那么JS原型链是什么呢:
  /* 这段话慢慢读, 从搞基程序设计三抄过来的,很重要, 实体书最好自己看一看哇;
  * ECMAScript中描述了原型链的概念, 并将原型链作为实现继承的主要方法, 基本思想是利用引用类型继承另一个引用类型的属性和方法。
  * 简单回顾一下构造函数,原型和实例的关系:每一个函数都有一个原型对象, 每一个原型对象都有一个指向构造函数的指针,
  * 而实例包含了一个指向原型对象的内部(不可见的)指针。 那么我们让原型对象等于另一个类型的实例, 那么这个原型对象将会包含指向
  * 另一个原型对象的指针,如果另一个原型对象又是指向了别的原型的一个实例, 这样层层嵌套, 就形成了原型链;
  * */  那么我们利用原型的原型链相互继承来写一个基本的例子:  
&!DOCTYPE html&
&title&&/title&
&meta charset="utf-8"&
//最好所有的代码自己打一遍, 增加印象;
function l ( arg ) {
console.log( arg );
var Fn = function() {
this.property = true;
Fn.prototype.getFnProperty = function() {
console.log( this.property );
var SubFn = function() {
this.subProperty = false;
//SubFn继承了Fn的实例
SubFn.prototype = new Fn();
//为实例添加额外的实例方法;
SubFn.prototype.getSubProperty = function(){
console.log(this.subProperty);
var subFn = new SubFn();
subFn.getFnProperty(); //输出了true
subFn.getSubProperty(); //输出了false
/*现在subFn的constructor 是
function () {
this.property =
所以要修正SubFn.prototype.constructor = SubFn
  原型式继承第二个例子:
&!DOCTYPE html&
&title&&/title&
&meta charset="utf-8"&
//最好所有的代码自己打一遍, 增加印象;
function l ( arg ) {
console.log( arg );
// 首先, 准备一个方法;
var inherit = function(o) {
if(!typeof o === "object")return;
function F () {}
F.prototype =
F.prototype.constructor = F;
return new F();
var Fn = function() {
this.property = true;
Fn.prototype.getFnProperty = function() {
console.log( this.property );
var SubFn = function() {
this.subProperty = false;
//SubFn继承了Fn的实例
SubFn.prototype = new Fn();
//为实例添加额外的实例方法;
SubFn.prototype.getSubProperty = function(){
console.log(this.subProperty);
var subFn = new SubFn();
//这个方法的内部, 临时创建了一个构造函数, 然后将传入的对象作为这个构造函数的原型, 最后返回一个临时的新实例;
//ECMASscript 5 有新增了一个Object.create 效果和inherit一模一样, 它可以接收第二个参数,
// 第二个参数要通过defineProperties的方式设置,会覆盖原型的属性, 比如:
Object.create(subFn, {
getFnProperty: {
var Fn = function() {};
//如果我们inherit传对象;
Fn.prototype = inherit( {0:0,1:1,2:2,3:3,4:4} );
l( new Fn ) //==&Fn {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, constructor: function(){....} 继承了哦
//如果我们给inherit传一个构造函数的实例;
Fn.prototype = inherit( new SubFn );
l(new Fn);
  有时候看到原型的各种引用会尿失禁, 引来引去的,坑爹啊, 不说了去洗裤子了....
  寄生组合式继承  
  组合继承是JS的常用继承模式, 但是也有自己的不足, 组合继承最大的问题的无论是什么情况下, 都会两次调用超类的构造函数;  一个是在创建子类原型的时候, 另一个是在子类构造函数的内部, &那么子类的原型会包含所有超类实例的全部属性,  寄生组合式继承就是为了解决子类原型包含所有超类实例全部属性这个问题而存在的;  
&!DOCTYPE html&
&title&&/title&
&meta charset="utf-8"&
//最好所有的代码自己打一遍, 增加印象;
function l ( arg ) {
console.log( arg );
var inherit = function(o) {
if(!typeof o === "object")return;
function F () {}
F.prototype =
F.prototype.constructor = F;
return new F();
//首先要准备inheritPrototype方法;
var util = util || {};
util.inherit =
util.inheritPrototype = function(subType, superType) {
var _prototype = this.inherit( superType.prototype );
_prototype.constructor = subT
subType.prototype = _
function F( name ) {
this.name =
this.type = "human";
this.habits = ["dance","code"];
F.prototype.laugh = function() {
console.log("heha!");
var InheritF = function() {
F.apply( this, arguments );
util.inheritPrototype(InheritF, F);
InheritF.prototype.letsGo = function() {
l("1,2,3,4")
var nono = new InheritF("nono");
nono.habits.push("read books");
l(nono.habits)
var nonono = new InheritF("nono");
l( nonono.habits );
//继承的方法千万种,万变不离其宗;
  JS各种使用了继承库的类库推荐, 可以加深印象:
  首先,&JS.Class&是一个mootools式的类工厂 基于 lunereaper&![[dawid.kraczkowski[at]gmail[dot]com]]&的项目进行修改, 让子类的实现更简洁;
&!DOCTYPE html&
&title&&/title&
&meta charset="utf-8"&
// 这个是库的源代码;
JS.Class = function(classDefinition) {
//返回目标类的真正构造器
function getClassBase() {
return function() {
//它在里面执行用户传入的构造器construct
//preventJSBaseConstructorCall是为了防止在createClassDefinition辅助方法中执行父类的construct
if (typeof this['construct'] === 'function' && preventJSBaseConstructorCall === false) {
this.construct.apply(this, arguments);
//为目标类添加类成员与原型成员
function createClassDefinition(classDefinition) {
//此对象用于保存父类的同名方法
var parent = this.prototype["parent"] || (this.prototype["parent"] = {});
for (var prop in classDefinition) {
if (prop === 'statics') {
for (var sprop in classDefinition.statics) {
this[sprop] = classDefinition.statics[sprop];
//为目标类添加原型成员,如果是函数,那么检测它还没有同名的超类方法,如果有
if (typeof this.prototype[prop] === 'function') {
var parentMethod = this.prototype[prop];
parent[prop] = parentM
this.prototype[prop] = classDefinition[prop];
//其实就是这样的Base = function() {};别想太多了;
var preventJSBaseConstructorCall = true;
var Base = getClassBase();
preventJSBaseConstructorCall = false;
createClassDefinition.call(Base, classDefinition);
//用于创建当前类的子类
Base.extend = function(classDefinition) {
//其实就是这样的Base = function() {};别想太多了;
preventJSBaseConstructorCall = true;
var SonClass = getClassBase();
SonClass.prototype = new this();//将一个父类的实例当作子类的原型
preventJSBaseConstructorCall = false;
createClassDefinition.call(SonClass, classDefinition);
SonClass.extend = this.
return SonC
//这是实际案例;
var Animal = JS.Class({
construct: function(name) {
this.name =
shout: function(s) {
console.log(s);
var animal = new Animal();
animal.shout('animal'); // animal
var Dog = Animal.extend({
construct: function(name, age) {
//调用父类构造器
this.parent.construct.apply(this, arguments);
this.age =
run: function(s) {
console.log(s);
var dog = new Dog("dog", 4);
console.log(dog.name);
dog.shout("dog"); // dog
dog.run("run"); // run
console.log(dog.constructor + "")
var Shepherd = Dog.extend({
statics: {//静态成员
TYPE: "Shepherd"
run: function() {//方法链,调用超类同名方法
this.parent.run.call(this, "fast");
console.log(Shepherd.TYPE);//Shepherd
var shepherd = new Shepherd("shepherd", 5);
shepherd.run();//fast
var a = new Animal("xx");
console.log(a.run);
&  &prototype这个( ▼-▼ )库以前牛逼着呢, 但是一百年河东一百年河西, prototype当前的版本是最新版本的1.7稳定版,prototype里面的类工厂创建的主代码也被我单独裁出来了, 源码也差不多, 源码有我加的注释,自己个人方便阅读, HTML代码的最后自己写的几种 创建类工厂的方式, 可以借鉴(我没看api, 源码就是api....)
&!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&
&html xmlns="http://www.w3.org/1999/xhtml"&
&meta http-equiv="Content-Type" content="text/ charset=utf-8" /&
&title&prototype Demo&/title&
var Class = (function() {
var IS_DONTENUM_BUGGY = (function(){
for (var p in { toString: 1 }) {
if (p === 'toString') return false;
return true;
Object.keys = Object.keys || (function() {
if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
var results = [];
for (var property in object) {
if (object.hasOwnProperty(property)) {
results.push(property);
Object.isFunction = function(fn) {
return typeof fn === "function";
function argumentNames() {
var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
.replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
.replace(/\s+/g, '').split(',');
return names.length == 1 && !names[0] ? [] :
function $A(iterable) {
if (!iterable) return [];
if ('toArray' in Object(iterable)) return iterable.toArray();
var length = iterable.length || 0, results = new Array(length);
while (length--) results[length] = iterable[length];
function update(array, args) {
var arrayLength = array.length, length = args.
while (length--) array[arrayLength + length] = args[length];
//wrapper表示的是现在的方法;
function wrap(wrapper) {
//this指向的返回的闭包;
var __method = this;
return function() {
//a是指把orginalFu和当前的参数混合成一个数组;
var a = update([__method.bind(this)], arguments);
return wrapper.apply(this, a);
Object.extend =
Function.prototype.argumentNames = argumentN
Function.prototype.wrap =
//把第二个参数的属性继承到第一个参数上;
function extend(destination, source) {
for (var property in source)
destination[property] = source[property];
function subclass() {};
function create() {
//相当于对参数进行
var parent = null, properties = $A(arguments);
//如果第一个是函数就把这个函数作为超类;
if (Object.isFunction(properties[0]))
parent = properties.shift();
//这个是返回的构造函数;
function klass() {
this.initialize.apply(this, arguments);
//为klass添加addMethods方法;
Object.extend(klass, Class.Methods);
//保存超类;
klass.superclass =
klass.subclasses = [];
if (parent) {
subclass.prototype = parent.
klass.prototype = new
//把当前的类保存到父级的超类, 有什么意义呢;
parent.subclasses.push(klass);
for (var i = 0, length = properties. i & i++)
klass.addMethods(properties[i]);
//避免没有initialize而报错;
if (!klass.prototype.initialize)
klass.prototype.initialize = function() {};
//这个避免constructor被properties覆盖了, 重新赋值;
klass.prototype.constructor =
function addMethods(source) {
var ancestor
= this.superclass && this.superclass.prototype,
properties = Object.keys(source);
//IE8以下可以遍历到toString和valueOf;
if (IS_DONTENUM_BUGGY) {
if (source.toString != Object.prototype.toString)
properties.push("toString");
if (source.valueOf != Object.prototype.valueOf)
properties.push("valueOf");
for (var i = 0, length = properties. i & i++) {
var property = properties[i], value = source[property];
//没有父级就没必要走下去了 , 如果有父级, 而且value不是function那么就没必要走了;
//如果你传:Class.create(Fn, {0:function($super){alert(1)},1:1,2:2,3:3,4:4})
//那么$super这个方法是指向ancestor的闭包, 只要执行$super那么超类的同名方法会被执行;
if (ancestor && Object.isFunction(value) &&
value.argumentNames()[0] == "$super") {
var method =
//返回一个闭包;
value = (function(m) {
return function() { return ancestor[m].apply(this, arguments); };
})(property).wrap(method);
如果不用简写的话,写成这样子也是ok的,他那么写, 一下子高端起来了,我C, 就是两个闭包哇;
var closureFn = (function(m) {
return function() { return ancestor[m].apply(this, arguments); };
})(property);
value = function() {
var args = Array.prototype.slice.call(arguments);
args.unshift( closureFn );
//是谁执行了value,当前的this就是谁,刚好是实例对象;
method.apply(this, args)
//修正这个闭包的valueOf为method这个方法....
value.valueOf = method.valueOf.bind(method);
value.toString = method.toString.bind(method);
//Class.create({0:0,1:1,2:2,3:3,4:4})会走这边;
this.prototype[property] =
return this;
create: create,
Methods: {
addMethods: addMethods
//__________________________________________
//创建一个类工厂
var Fn = Class.create({
method0 : function() {
console.log("method0");
console.log(arguments);
method1 : function() {
console.log("method1");
console.log(arguments);
//实例化该类工厂;
var fn = new Fn();
fn.method0(); //输出 : method0 []
fn.method1(0,1,2,3,4); //输出 : method1 , [0, 1, 2, 3, 4];
//SubFn , 继承了Fn;
var SubFn = Class.create(Fn, {
method2 : function() {
console.log(2)
(new SubFn).method2() //输出 :2
//__________________________________________
//__________________________________________
//子类调用超类的同名方法的使用;
var Fn = Class.create({
0:function(){
console.log(arguments);
return "hehe";
//Fn0继承了Fn;
var Fn0 = Class.create(Fn, {
0:function($super,arg0,arg1,arg2,arg3){
console.log( $super( arguments ) );
console.log(arg0+" "+arg1+" "+arg2+ " " +arg3);
//实例化Fn0,执行0的方法传进去几个参数, 都会传到Fn的0方法里面, Fn0如果叫做$super的参数, $super代表超类的同名方法;
(new Fn0)[0](10,9,8,7); //输出 三个字段,包含超类的的arguments和超类的返回,以及子类的输出: arguments5 , hehe , 10,9,8,7
console.log(new Fn0); //输出一个实例;
//__________________________________________
//为Fn0的原型新加一个&nono&方法;
Fn0.addMethods({"nono" : function() {
console.log("you are super man");
//实例化原型执行nono方法:
var instance = new Fn0;
instance.nono() //输出了:
//__________________________________________
//我们现在的类方法和属性都是原型上继承下来的,只要超类的方法或者属性发生了改变, 那么子类的方法也发生了改变;
Fn0.prototype.nono = "someting wrong!!";
instance.nono // 输出了== &"someting wrong!!" ...卧槽,这样可不行啊;
//我们需要创建私有属性
var FnBar = Class.create(Fn,{
initialize : function() {
this.hehe = "haha",
this.say = function( words ) {
console.log( words ||this.hehe );
var instanceBar = new FnBar();
var FnFoo = Class.create(FnBar,{
initialize : function() {
this.say = function() {
console.log("fuck! you duck!!!");
//prototype是基于原型继承原型的库, 而不是基于原型继承实例, 所以用起来也挺方便的;
(new FnFoo).say();
  这款继承创建的作者是jQ的作者,你懂的, 不绕;
  & 《《== 这个是代码的源地址:
&!DOCTYPE html&
&title&&/title&
&meta charset="utf-8"&
/* source: https://gist.github.com/shakyShane/5944153
* Simple JavaScript Inheritance for ES 5.1 ( includes polyfill for IE & 9 )
* based on http://ejohn.org/blog/simple-javascript-inheritance/
(inspired by base2 and Prototype)
* MIT Licensed.
(function (global) {
"use strict";
if (!Object.create) {
Object.create = (function () {
function F() {
return function (o) {
if (arguments.length !== 1) {
throw new Error("Object.create implementation only accepts one parameter.");
F.prototype =
return new F();
var fnTest = /xyz/.test(function () {
/* jshint ignore:start */
/* jshint ignore:end */
}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
function BaseClass() {
// Create a new Class that inherits from this class
BaseClass.extend = function (props) {
var _super = this.
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
var proto = Object.create(_super);
// Copy the properties over onto the new prototype
for (var name in props) {
// Check if we're overwriting an existing function
proto[name] = typeof props[name] === "function" &&
typeof _super[name] === "function" && fnTest.test(props[name]) ?
(function (name, fn) {
return function () {
var tmp = this._
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super =
})(name, props[name]) :
props[name];
// The new constructor
var newClass = function () {
if (typeof this.init === "function") {
this.init.apply(this, arguments);
// Populate our constructed prototype object
newClass.prototype =
// Enforce the constructor to be what we expect
proto.constructor = newC
// And make this class extendable
newClass.extend = BaseClass.
return newC
global.Class = BaseC
var Fn = function() {};
//对继承的插件进行引用;
Fn.extend = window.Class.
Fn.prototype.lala = 1;
Fn.prototype.say = function() {
alert( this.lala );
var Foo = Fn.extend({
init:function(){
this.name="nono"
dayDudu:function(){
alert(this.dudu);
  执行 new Foo打印出来对象结构如下:
  pjs这个类工厂的github地址是:&,挺有名的js类工厂库, 写了源码分析, 关于代码我就不吐槽了,你看了就懂了, 不过真心挺方便的;
&!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&
&html xmlns="http://www.w3.org/1999/xhtml"&
&meta http-equiv="Content-Type" content="text/ charset=utf-8" /&
&title&无标题文档&/title&
var P = (function(prototype, ownProperty, undefined) {
// helper functions that also help minification
function isObject(o) { return typeof o === 'object'; }
function isFunction(f) { return typeof f === 'function'; }
// a function that gets reused to make uninitialized objects
function BareConstructor() {}
function P(_superclass /* = Object */, definition) {
// handle the case where no superclass is given
//如果没有超类,那么超类就设置为Object,definition为对象或者是fn都行
//是对象的话会把对象的所有属性和方法复制到返回的类原型,
//是函数会传给函数有关返回类的原型(引用)等参数;
if (definition === undefined) {
definition = _
_superclass = O
// C is the class to be returned.
// It delegates to instantiating an instance of `Bare`, so that it
// will always return a new instance regardless of the calling
// context.
TODO: the Chrome inspector shows all created objects as `C`
rather than `Object`.
Setting the .name property seems to
have no effect.
Is there a way to override this behavior?
//无论你是使用 new还是直接运行都会返回C的实例;
function C() {
var self = new B
//如果创建的实例有init会执行init方法, init这个函数里面放的是私有的属性;
if (isFunction(self.init)) self.init.apply(self, arguments);
// C.Bare is a class with a noop constructor.
Its prototype is the
// same as C, so that instances of C.Bare are also instances of C.
// New objects can be allocated without initialization by calling
// `new MyClass.Bare`.
function Bare() {}
C.Bare = B
// Set up the prototype of the new class.
//指定超类的原型 到BareConstructor, 公用一个函数到BareConstructor,专门用来实例化超类;
var _super = BareConstructor[prototype] = _superclass[prototype];
//proto为Bare原型的引用;
//实例化的超类的实例指向了C和Bare的Prototype,主要是Bare的prototype,因为类工厂返回的实例就是Bare的实例;
var proto = Bare[prototype] = C[prototype] = new BareC
// other variables, as a minifier optimization
// set the constructor property on the prototype, for convenience
proto.constructor = C;
//这个超类的mixin会重新调用P返回原型重新赋值给Bare和C,返回C, 方便无new实例化;
C.mixin = function(def) {
Bare[prototype] = C[prototype] = P(C, def)[prototype];
//C.open 这个方法可以用来为这个类添加原型
return (C.open = function(def) {
//重新定义extensions为一个空对象, C.open打开或者第一次打开的时候重新定义, 写成var extensions = {}; 也行,个人感觉没有问题;
extensions = {};
if (isFunction(def)) {
// call the defining function with all the arguments you need
// extensions captures the return value.
//proto指向了C和Bare的原型,要添加原型就往这个对象extend方法即可;
//也可以为这个函数返回对象作为原型的属性;
extensions = def.call(C, proto, _super, C, _superclass);
else if (isObject(def)) {
// if you passed an object instead, we'll take it
extensions =
//继承属性到超类;
// ...and extend it
if (isObject(extensions)) {
for (var ext in extensions) {
if (ownProperty.call(extensions, ext)) {
proto[ext] = extensions[ext];
//没有init就把init设置为超类;
// if there's no init, we assume we're inheriting a non-pjs class, so
// we default to applying the superclass's constructor.
if (!isFunction(proto.init)) {
proto.init = _
})(definition);
// ship it
// as a minifier optimization, we've closured in a few helper functions
// and the string 'prototype' (C[p] is much shorter than C.prototype)
})('prototype', ({}).hasOwnProperty);
//直接创建一个类
var Fn = P({
console.log( new Fn() ); //输出: Bare {0: 0, 1: 1, constructor: function, init: function}
console.log( (new Fn()).init() ) //如果没有init, 那么init出来默认为 Object {}
//让FnBar继承Fn
var FnBar = P(Fn,{
console.log( new FnBar ); //输出: Bare {2: 2, 3: 3, 4: 4, constructor: function, 0: 0, 1: 1, init: function}
//为FnFoo添加额外的方法和属性;
var FnFoo = FnBar.open({
console.log( new FnFoo ); //输出: Bare {2: 2, 3: 3, 4: 4, 5: 5, 6: 6, constructor: function, 0: 0, 1: 1, init: function}
//各种各样的继承方式 你都可以用
var FnFoo0 = FnFoo.mixin({
console.log( new FnFoo0); //输出: Bare {7: 7, 8: 8, constructor: function, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 0: 0, 1: 1, init: function}
//____________________________________-_-_______________
//直接创建一个类
var Fn = P({
init : function() {
this.name = "nono";
console.log(this);
(new Fn).init(); // 输出: Bare {name: "nono", 0: 0, 1: 1, constructor: function, init: function};
//通过C.open的方式为Fn添加超类
var FnBar = Fn.open(function(
proto, _super, C, _superclass ) {
proto.style = "gangnanStyle";
proto.job = "superWebDevoloper";
proto.say = function() {
console.log( this.job + " __ " + this.job);
(new FnBar).say(); //输出: superWebDevoloper __ superWebDevoloper
//通过传入function的方式为构造函数添加超类;
// 该方法不但继承了FnBar, 而且在第二个Fn的参数中为构造函数添加了sayWhat方法, 该函数的返回也会作为原型被添加到类原型上。。。。;
var FF = P(FnBar, function( proto, _super, C, _superclass ) {
proto.sayWhat = function() {
console.log( "funky world!" );
sayHi : function() {
console.log( "monkey world!" );
console.log( new FF );//输出: Bare {name: "nono", constructor: function, sayWhat: function, 0: 0, 1: 1, init: function, style: "gangnanStyle"&};
(new FF).sayWhat();
//输出: funky world!
(new FF).sayHi();
//输出:monkey world!
  每一个人都要有一片属于自己的宁静天空, 在那里没有压力, 只有自己 , 和自己身体的对话;
  最后提供一些参考的链接:
    javascript 类属性、类方法、类实例、实例属性、实例方法、prototype、__proto__ 测试与小结: 
      
&    JS的构造函数:
      
    浅析Javascript原型继承:
      
阅读(...) 评论()
再过一百年, 我会在哪里?

我要回帖

更多关于 jswebsocket 的文章

 

随机推荐