首頁  >  文章  >  web前端  >  JS物件導向(3)之Object類,靜態屬性,閉包,私有屬性, call與apply的使用,繼承的三種實作方法_javascript技巧

JS物件導向(3)之Object類,靜態屬性,閉包,私有屬性, call與apply的使用,繼承的三種實作方法_javascript技巧

WBOY
WBOY原創
2016-05-16 15:13:411417瀏覽

1.Object類別

在JS中,Object是所有類別的基底類,使用Object類別來建立自訂物件時,可以無需定義建構子(constructor,prototype,hasOwnProperty(property))

var per = new Object();
per.name = 'zhangsan';
per.age = ;
alert(per.name + per.age);

我們想要在程式中得到一個物件變量,只要能儲存大量資料即可,這個時候,我們可以考慮使用Object類別。 Object類別避免了建構器的定義。 Object類別下另一個常用的屬性:hasOwnProperty

var per = new Object();
per.name = 'zhangsan';
per.age = ;
if per.hasOwnProperty('email'){
alert('具有email');
}else{
alert('无email');
}

2.靜態屬性

在有些物件導向的語言當中,可以使用static關鍵字定義類別的靜態屬性或是靜態方法,在JS中,可以進行模擬。

文法:

類別名稱.屬性名稱

類別名稱.屬性=function(){}

function Person(){
}
Person.count = ;
var p = new Person();
Person.count++;
var p = new Person();
Person.count++;
var p = new Person();
Person.count++;
alert(Person.count);

新增靜態屬性與靜態方法:

function Person(){
Person.count++; //静态属性
Person.getCount=function(){ //静态方法
alert('当前共有' + Person.count + '个人');
}
}
Person.count = ;
var p = new Person();
var p = new Person();
var p = new Person();
Person.getCount();

3.閉包

概念:所謂閉包,指的是一個擁有許多變數和綁定了這些變數的環境的表達式(通常是一個函數),因此這些變數也是該表達式的一部分。

提出一個問題:

function display(){
var i=; 
}
display();
//在这里,想访问局部变量i

在全域中,不能存取局部變數i,因為作用域不同,而且,在display函數執行完畢後,局部變數i會被回收。 閉包的功能:「存取局部變數」與「使變數所佔的記憶體不被釋放」

//例
function fn(){
function fn(){
alert('hello');
}
return fn; //返回fn函数首地址
}
var test=fn(); //test也指向了fn函数的首地址
test();

透過例1我們知道:變數是可以指向函數的首位址的,函數也可以回傳另一個函數的首位址。

//例
function fn(){
var i = ;
function fn(){
alert(i);
}
return fn; //返回fn函数首地址
}
var test=fn(); //test也指向了fn函数的首地址
test();

透過例2我們知道:使用一個拒不函數包含變數i,這樣局部變數i的記憶體就不會被回收。

//例
function fn(){
var i = ;
function fn(){
alert(i++);
}
return fn; //返回fn函数首地址
}
var test=fn(); //test也指向了fn函数的首地址
test();
test();
test();

在例3中,因為i的記憶體永遠不會被回收,所以每次呼叫fn2,i的值會+1。運行的結果是彈出10,彈出11,彈出12。

閉包的原理:在例3中,共有三個作用域:全域作用域,fn1的作用域,fn2的作用域。在全域作用域裡有test=fn1(),其實這句話就相當於test=fn2。在fn1作用域裡有 var i=10和return fn2,在fn2作用域例有alert(i++)。當全域作用域下的test=fn1()執行時,test指向了fn2的作用域,這時候fn2作用域下的i被全局作用域鉤住,根據作用域鏈的法則,fn2下並沒有定義i ,所以在fn2下的i往上一層作用域上找,找到了fn1作用域下的var i=10。所以全域的test鉤住了fn2的i,fn2的i鉤住了fn1的i,所以fn1運行完畢後,不會被回收。

4.私有屬性

在物件導向思想中,對於有些敏感的,不想公開的成員可以定義為私有的,在JavaScript中可以模擬這個功能。

文法:

function Person(p_name){
var name = p_name;
this.age
}

var :私有

this :公有

function Person(p_name,p_age){
this.name = p_name;
var age = p_age;
}
var p = new Person('zhangsan',);
alert(p.name);
alert(p.age);

在上面這個範例中,我們想用 var 來表示私有成員屬性,但 Person 建構子執行完畢後, age 會被回收,不能當做成員屬性來使用。

function Person(p_name,p_age){
this.name = p_name;
var age = p_age;
this.setAge=function(a){
age = a;
}
this.getAge=function(){
return(age);
}
}
var p = new Person('zhangsan',);
p.setAge();
alert(p.getAge());

this.setAge和this.getAge兩個方法使用到了局部變數age,所以age不會被回收。

如果只有set方法,表示該屬性是只寫屬性。

如果只有get方法,表示該屬性是唯讀屬性。

5.call和apply的使用

call和apply的功能:使用指定的物件呼叫目前函數。 call和apply的功能完全相同,只是在語法上略有不同。

文法:

call([thisObj[,arg1[,arg2[,argN]]]])

第一個參數:函數執行時,this指向誰

後面的參數:依需求順序指定

apply([thisObj[,argArray]])

第一個參數:函數執行時,this指向誰

第二個參數:數組,表示參數集合

在js中,函數有幾種呼叫形式:

Person(); //Person内的this指向window
var p=new Person(); //Person内的this指向p
per.Person(); //Person内的this指向per
function Person(p_name,p_age){
this.name = p_name;
this.age = p_age;
}
function speak(){
alert(this.name + this.age);
}
var p = new Person('zhangsan',);
//speak(); 这样调用this指向window
//p.speak(); p对象没有speak属性

使用call和apply來呼叫

function Person(p_name,p_age){
this.name = p_name;
this.age = p_age;
}
function speak(){
alert(this.name + this.age);
}
var p = new Person('zhangsan',);
speak.call(p);
speak.apply(p);

call和apply在執行時做了兩件事:1)將函數內部this指向了第一個參數 2)呼叫函數

另外:還可以這樣解決問題:

P1.say=speak;

P1.say();

這樣解決和上面解決方法有本質上的區別:

上面的解決方法是直接呼叫speak函數,只不過函數內部this的指向發生改變。

下面的解決方法會為p1物件增加屬性,p1物件的「體積」就會變大。

舉例說明:

<script>
function fn(){
this.style.color='red';
}
function fn(){
this.style.fontSize='px';
}
window.onload=function(){
document.getElementById('btn').onclick=function(){
var div = document.getElementById('div');
fn.call(div);
fn.apply(div);
};
};
</script>
<div id='div'>hello javascript</div>
<input type='button' id='btn' value='确定'>

6.继承的三种实现方法

概念:在有些面向对象语言中,可以使用一个类(子类)继承另一个类(父类),子类可以拥有父类的属性和方法,这个功能可以在js中进行模拟。

三种方法:

第一种:扩展Object方法

Object.prototype.方法=function(父类对象){
for(var i in 父类对象){
this[i] = 父类对象[i];
} 
};

举例说明:

Object.prototype.ext=function(parObject){
//循环遍历父类对象所有属性
for(var i in parObject){
//为子类对象添加这个遍历到的属性
//它的值是父类对象这个属性的属性值
this[i] = parObject[i];
}
}
function Person(p_name,p_age){
this.name=p_name;
this.age=p_age;
this.speak=function(){
alert(this.name+this.age);
}
}
function Student(p_no){
this.no=p_no;
this.say=function(){
alert(this.no+this.name_this.age);
}
}
var stu = new Student();
stu.ext(new Person('xiaoqiang',));
stu.speak();
stu.say();

第二种:使用call和apply方法

语法:

父类构造器.call(this,.......);

function Person(p_name,p_age){
this.name=p_name;
this.age=p_age;
this.speak=function(){
alert(this.name+this.age);
}
}
function Student(p_no,p_name,p_age){
this.no=p_no;
this.say=function(){
alert(this.name+this.age+this.no);
}
Person.call(this,p_name,p_age);
}
var stu = new Student(,'zhagsan',);
stu.speak();
stu.say();

第三种:原型继承

语法:

子类.prototype = new 父类();

function Person(p_name,p_age){
this.name=p_name;
this.age=p_age;
this.speak=function(){
alert(this.name+this.age);
}
}
function Student(p_no){
this.no=p_no;
this.say=function(){
alert(this.name+this.age+this.no);
}
}
Student.prototype = new Person('wangwu',);
var stu = new Student();
stu.speak();
stu.say();

以上内容给大家介绍了JS面向对象(3)之Object类,静态属性,闭包,私有属性, call和apply的使用,继承的三种实现方法,希望对大家有所帮助!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn