面向對象之構造函數
結構:
function 構造函數() {
this.屬性 = valve
}
構造函數.prototype.方法 = function() {
}
var 對象1 = new 構造函數();
對象1.方法();
eg :
function Person() {
this.name = 'bob';
}
Person.prototype.sayName = function() {
alert(this.name)
}
var p1 = new Person();
alert(p1.name); // bob
p1.sayName(); //bob
tips : 當`new`去調用一個函數,函數中的`this`就是`new`創建出來的對象,而且函數的返回值就是`this`,也就是對象(隱式返回)
如何改寫面向對象的選項卡
原則:
先寫出普通的方法,再改成面向對象的寫法。
1、普通的方法
(1)儘量不要出現函數嵌套函數
(2)可以有全局變量
(3)把onload中不是賦值的語句放到單獨函數中。
2、改成面向對象
(1)全局變量就是屬性
(2)函數就是方法
(3)onload中創建對象
(4)改this指向問題,儘量讓this指向對象
eg:
<body>
<input type="button" value="選項1" class="active">
<input type="button" value="選項2">
<input type="button" value="選項3">
<div class="box1" style="display:block">內容一</div>
<div class="box2">內容二</div>
<div class="box3">內容三</div>
</body>
/*面向對象寫法*/
window.onload = function(){
var t1=new Tab('tab1');
t1.init();
t1.autoPlay(2000);
var t2=new Tab('tab2'); //新弄的一個
t2.init();
t2.autoPlay(1000);
}
function Tab(id) {
this.oTaba=document.getElementById(id);
this.aInp=this.oTaba.getElementsByTagName('input');
this.aDiv=this.oTaba.getElementsByTagName('div');
this.iNow=0;
}
Tab.prototype.init = function() {
var This=this;
for (var i = 0; i < this.aInp.length; i++) {
this.aInp[i].index=i;
this.aInp[i].οnclick=function() {
console.log(this)
This.change(this);
};
};
}
Tab.prototype.change = function(obj) {
for (var i = 0; i < this.aInp.length; i++) {
this.aInp[i].className='';
this.aDiv[i].className='';
};
obj.className='active';
this.aDiv[obj.index].className='active';
};
Tab.prototype.autoPlay = function (time){
var This=this;
setInterval(function(){
This.iNow++;
if (This.iNow == This.aInp.length) {
This.iNow=0;
};
for (var i = 0; i < This.aInp.length; i++) {
This.aInp[i].className='';
This.aDiv[i].className='';
};
This.aInp[This.iNow].className='active';
This.aDiv[This.iNow].className='active';
},time)
}
包裝對象
1、系統對象也是基於原型prototype
的程序
2、基本類型都有自己對應的包裝對象 : String 、 Number、 Boolean(除了null 和 undefined)
var str = 'abc';
str.charAt(0); //基本類型會找到對應的包裝對象,包裝對象把所有的屬性和方法給了基本類型,然後包裝對象消失
原型鏈
1 、實例對象與原型之間的鏈接,叫做原型鏈。最外層是Object.prototype
2、proto(原型鏈,隱式連接) ,先找普通方法,再找原型。最後找最外層
3、Object對象類型時原型鏈的最外層
面向對象的一些屬性和方法
1、hasOwnPrototype(); 看是不是自身下面的屬性和方法,不會查找原型下面的屬性和方法
2、constructor : 查看對象的構造函數。
function Person() {
}
Person.prototype.name = 'Bob';
Person.prototype.age = 100;
Person.prototype.constructor = Person //自動生成,不要手動添加
var p1 = new Person();
alert( p1.constructor ) //function Person() {}
/** tips :寫成對象字面量時 指向問題 **/
function Person() {
}
Person.prototype = {
name : 'Bob',
age : 100
}
var p1 = new Person();
alert( p1.constructor ) //function Object() {[native code]}
解決辦法 :手動修改指向
Person.prototype = {
constructor : Person,
name : 'Bob',
age : 100
}
3、for in
找不到系統自帶的屬性,比如constructor,自己寫constructor也找不到
4、instanceof : 運算符,對象與構造函數在原型鏈上是否有聯繫,任何對象instanceof Object 都是true
5、toString : Object上的方法,也可用作類型的判斷(最靠譜);系統對象下面都是自帶的,寫在構造函數prototype下的,自己寫的都是通過原型鏈找Object下面的(Object.prototype)
var arr = [];
alert( Object.prototype.toString.call(arr) ) // '[object Array]'
繼承
概念 : 在原有對象的基礎上,略作修改,得到一個新的對象,並且不影響原有對象
常用的繼承方式:
屬性的繼承 : call
方法的繼承 :for in (淺複製與深複製)
function Person (name,age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function () {
alert(this.name)
}
Person.prototype.sayAge = function () {
alert(this.age)
}
function Start (name, age, job) {
Person.call(this,name,age); //屬性繼承
this.job = job;
}
extend(Start.prototype,Person.prototype); //方法繼承,淺複製
Start.prototype.sayJob = function () {
alert(this.job);
}
function extend (obj1,obj2) {
for (var attr in obj2) {
obj1[attr] = obj2[attr]
}
}
var s1 = new Start('黃曉明',20,'stat');
s1.sayAge();
s1.sayJob();
var p1 = new Person('小球',100);
alert(p1.name);
繼承的其他方式
1、類式繼承 : 利用構造函數繼承的方式
類 : js是沒用類概念的,把構造函數看做是類
子構造函數.prototype = new 父構造函數 //繼承的屬性和方法
存在的問題 : ,
(1)constructor的指向問題 (需手動指向)
(2)實例1 的屬性方法修改會影響 實例2 (想想原型鏈的查找 , 屬性和方法分開繼承)
function Person1(name) {
this.name = name;
this.job = 'worker';
}
Person1.prototype.sayName = function() {
alert(this.name);
}
Person1.prototype.sayJob = function() {
alert(this.job);
}
function Person2(name,age) {
Person1.call(this,name,age); //繼承屬性
this.age = age;
this.job = 'student';
}
/** 下面四行重點,前三行繼承方法,第四行解決指向問題 **/
var F = function(){};
F.prototype = Person1.prototype;
Person2.prototype = new F();
Person2.prototype.constructor = Person2;
Person2.prototype.sayAge = function() {
alert(this.age);
}
var p1 = new Person2('小強','255');
alert(p1.name);
p1.sayName();
p1.sayAge();
2、原型繼承 : 藉助原型來實現對象繼承對象
function Person() {
this.name = 'bob';
this.job = 'worker';
}
Person.prototype.sayName = function() {
alert(this.name);
}
Person.prototype.sayJob = function() {
alert(this.job);
}
var p2 = cloneObj(Person);
p2.name = 'xiaohua';
p2.age = 289;
p2.sayName();
function cloneObj(obj) {
var F = function(){};
F.prototype = obj.prototype;
return new F();
}
組件開發
組件開發 : 多組對象,像兄弟之間的關係,代碼複用(UI組件,功能組件)
默認參數 : 寫在構造函數中,普通方法
配置參數 : 寫在參數中
//組件開發彈出框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
* {margin: 0;padding: 0}
.loading1 {border: 1px solid #000;position: absolute;left: 0;top: 0;z-index: 10}
.loading1 p {width: 100%;height: 40px;background: #0cf}
.loading1 p .close {float: right;}
#mark {width: 100%; height: 100%; position: absolute; left: 0; top: 0; background: rgba(0,0,0,.4);}
</style>
<script type="text/javascript">
window.onload = function() {
var aInp = document.getElementsByTagName('input');
aInp[0].onclick = function() {
var l1 = new Load();
l1.init({
iNow : 1,
drag : true
})
}
aInp[1].onclick = function() {
var l2 = new Load();
l2.init({
iNow : 2,
w : '100',
h : '400',
dir : 'right',
title : '廣告'
});
}
aInp[2].onclick = function() {
var l3 = new Load();
l3.init({
iNow : 3,
title : '推廣',
mark : true
})
}
}
function Load() {
this.obj = null;
this.mark = null;
this.disX = 0;
this.disY = 0;
this.settings = {
w : '300',
h : '300',
dir : 'center',
title : '登陸',
mark : false,
toDown : function(){},
toMove : function(){},
toUp : function(){}
}
}
Load.prototype.json = {}; // 處理多次點擊多次添加的問題
Load.prototype.init = function(opt) {
var This = this;
extend(this.settings , opt);
if (this.json[opt.iNow] == undefined) {
this.json[opt.iNow] = true;
}
if (this.json[opt.iNow]) {
this.cresteData();
this.json[opt.iNow] = false;
};
}
Load.prototype.cresteData = function() {
this.obj = document.createElement('div');
this.obj.className = 'loading1';
this.obj.innerHTML = '<p><span>登陸</span><span class="close">X</span></p>';
document.body.appendChild(this.obj);
this.fnMark();
this.setData();
this.drag();
this.fnClose();
}
Load.prototype.setData = function() {
var oTitle = this.obj.getElementsByTagName('span')[0];
this.obj.style.width = this.settings.w + 'px';
this.obj.style.height = this.settings.h + 'px';
oTitle.innerHTML = this.settings.title;
if ( this.settings.dir == 'center' ) {
this.obj.style.left = ( viewWidth() - this.obj.offsetWidth )/2 + 'px';
this.obj.style.top = ( viewHeight() - this.obj.offsetHeight )/2 + 'px';
}else if ( this.settings.dir == 'right' ) {
this.obj.style.left = ( viewWidth() - this.obj.offsetWidth ) + 'px';
this.obj.style.top = ( viewHeight() - this.obj.offsetHeight ) + 'px';
}
}
Load.prototype.fnClose = function() {
var This = this;
var oClose = this.obj.getElementsByTagName('span')[1];
oClose.onclick = function (){
document.body.removeChild( This.obj );
This.json[This.settings.iNow] = true;
console.log( This.settings )
if ( This.settings.mark ) {
document.body.removeChild( This.mark );
};
}
}
Load.prototype.fnMark = function() {
if (this.settings.mark == true ) {
this.mark = document.createElement('div');
this.mark.id = 'mark';
document.body.appendChild(this.mark)
};
}
Load.prototype.drag = function (){
var This = this;
if (this.settings.drag) {
this.obj.onmousedown = function(ev) {
var ev = ev || window.event;
This.fnDown(ev);
// This.settings.toDown();
return false;
}
};
}
Load.prototype.fnDown = function(ev) {
var This=this;
this.disX = ev.clientX - this.obj.offsetLeft;
this.disY = ev.clientY - this.obj.offsetTop;
document.onmousemove = function(ev) {
var ev = ev || window.event;
This.fnMove(ev);
// This.default.toMove();
}
document.onmouseup = function(ev) {
var ev = ev || window.event;
This.fnUp();
// This.default.toUp();
}
}
Load.prototype.fnMove = function(ev) {
var iLeft = ev.clientX - this.disX;
var iTop = ev.clientY - this.disY;
if (iLeft < 0) {
iLeft = 0;
}else if (iLeft > viewWidth()-this.obj.offsetWidth) {
iLeft = viewWidth()-this.obj.offsetWidth;
}
this.obj.style.left = iLeft + 'px';
this.obj.style.top = iTop + 'px';
}
Load.prototype.fnUp = function() {
document.onmousemove = null;
document.onmouseup = null;
}
function extend (obj1,obj2) {
for(var attr in obj2){
obj1[attr] = obj2[attr]
}
}
function viewWidth() {
return document.documentElement.clientWidth;
}
function viewHeight() {
return document.documentElement.clientHeight;
}
</script>
</head>
<body>
<input type="button" value="1" />
<input type="button" value="2" />
<input type="button" value="3" />
<!-- <div class="loading1">
<p><span>登陸</span><span class="close">X</span></p>
</div> -->
<!-- <div id="mark"></div> -->
</body>
</html>
//組件開發選項卡
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
#tab1,#tab2,#tab3 {width: 300px;height: 300px;}
#tab1 div,#tab2 div,#tab3 div {width: 300px;height: 200px;border: 1px solid #000;display: none;}
input {width: 60px;height: 30px;}
.active {background: red}
</style>
<script type="text/javascript">
window.onload = function() {
var t1 = new Tab();
t1.init({
id : 'tab1',
events : 'onclick'
});
var t2 = new Tab();
t2.init({
id : 'tab2',
events : 'onmouseover'
})
t2.delay();
var t3 = new Tab();
t3.init({
id : 'tab3',
events : 'onmouseover'
});
t3.setIndex(1);
}
function Tab() {
this.obj = null;
this.aBtn = null;
this.aBox = null;
this.timer = null;
this.settings = {
events : 'onclick'
}
}
Tab.prototype.init = function(opt) {
extend(this.settings,opt)
this.obj = document.getElementById(opt['id']);
this.aBtn = this.obj.getElementsByTagName('input');
this.aBox = this.obj.getElementsByTagName('div');
this.change();
}
Tab.prototype.change = function() {
var This = this;
for (var i = 0; i < This.aBtn.length; i++) {
This.aBtn[i].index = i;
This.aBtn[i][This.settings.events] = function() {
var _this = This;
for (var i = 0; i < _this.aBtn.length; i++) {
_this.aBtn[i].className = '';
_this.aBox[i].style.display = 'none';
};
this.className = 'active';
_this.aBox[ this.index ].style.display = 'block';
}
};
}
Tab.prototype.delay = function() {
var This = this;
for (var i = 0; i < this.aBtn.length; i++) {
this.aBtn[i].index = i;
this.aBtn[i].onmouseout = function() {
clearTimeout(This.timer);
}
this.aBtn[i][this.settings.events] = function() {
var _index = this.index;
This.timer = setTimeout(function(){
toDelay(_index)
},200)
}
}
function toDelay(index) {
for (var i = 0; i < This.aBtn.length; i++) {
This.aBtn[i].className = '';
This.aBox[i].style.display = 'none';
};
This.aBtn[index].className = 'active';
This.aBox[index ].style.display = 'block';
}
}
Tab.prototype.setIndex = function(index) {
for (var i = 0; i < this.aBtn.length; i++) {
this.aBtn[i].className = '';
this.aBox[i].style.display = 'none'
};
this.aBtn[index].className = 'active';
this.aBox[index].style.display = 'block'
}
function extend(obj1,obj2) {
for(var attr in obj2) {
obj1[attr] = obj2[attr]
}
}
</script>
</head>
<body>
<div id="tab1">
<input type="button" value="1" class="active" />
<input type="button" value="2" />
<input type="button" value="3" />
<div style="display: block;">111111111</div>
<div>22222222</div>
<div>33333333</div>
</div>
<div id="tab2">
<input type="button" value="1" class="active" />
<input type="button" value="2" />
<input type="button" value="3" />
<div style="display: block;">111111111</div>
<div>22222222</div>
<div>33333333</div>
</div>
<div id="tab3">
<input type="button" value="1" class="active" />
<input type="button" value="2" />
<input type="button" value="3" />
<div style="display: block;">111111111</div>
<div>22222222</div>
<div>33333333</div>
</div>
</body>
</html>
自定義事件 :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript">
window.onload = function () {
var oDiv = document.getElementById('div1');
var oSpan = document.getElementById('span1');
bindEvent(oDiv,'click',function(){
alert(1)
});
bindEvent(oDiv,'click',function(){
alert(2)
});
bindEvent(oSpan,'show',function(){
alert(3)
});
bindEvent(oSpan,'show',function(){
alert(4)
});
bindEvent(oSpan,'hide',function(){
oSpan.style.background = 'red';
});
fireEvenet(oSpan,'hide')
function bindEvent(obj,events,fn) { //不完善,比如this指向
// obj :圖書館的樓層
// events :圖書的分類(書架)
// fn :一本書
obj.listener = obj.listener || {};
obj.listener[events] = obj.listener[events] || [];
obj.listener[events].push(fn);
if (obj.addEventListener) {
obj.addEventListener(events,fn,false)
}else{
obj.attachEvent('on'+events,fn)
}
}
function fireEvenet(obj,events) { //主動觸發函數
for (var i = 0; i < obj.listener[events].length; i++) {
console.log(obj.listener[events])
obj.listener[events][i]();
};
}
}
</script>
</head>
<body>
<div id="div1">div</div>
<span id="span1">span</span>
</body>
</html>