首頁 web前端 js教程 JavaScript物件導向精要

JavaScript物件導向精要

Feb 04, 2017 pm 05:49 PM
javascript 物件 面向

資料型別

在JavaScript中,資料型別分為兩類:

原始型別:保存一些簡單數據,如true,5等。 JavaScript共有5中原始型別:

●boolean:布爾,值為true或false

●number:數字,值為任何整數會浮點數值

●string:字串,值為由單引號或雙引號括出的單一字元或連續字元(JavaScript不區分字元類型)

●null:空白類型,其僅有一個值:nulll

●undefined:未定義,其僅有一個值:undefined

var name = "Pomy";
var blog = "http://www.ido321.com";
var age = 22;
alert(typeof blog); //"string"
alert(typeof age); //"number"
登入後複製

原始類型的值是直接保存在變數中,並可以用typeof進行檢測。但是typeof對null的偵測是回傳object,而不是回傳null:

//弹出Not null
if(typeof null){
alert("Not null");
}else{
alert("null");
}
登入後複製

所以偵測null時,最好用全等於(===),其還能避免強制型別轉換:

console.log("21" === 21); //false
console.log("21" == 21); //true
console.log(undefined == null); //true
console.log(undefined === null); //false
登入後複製

對於字串、數字或布林值,其都有對應的方法,這些方法來自於對應的原始封裝類型:String、Number和Boolean。原始封裝類型將會自動建立。

var name = "Pomy";
var char = name.charAt(0);
console.log(char); //"P"
登入後複製

在JavaScript引擎中發生的事情:

var name = "Pomy";
var temp = new String(name);
var char = temp.charAt(0);
temp = null;
console.log(char); //"P"
登入後複製

字串物件的引用在用完之後立即被銷毀,所以不能給字串添加屬性,並且instanceof檢測對應類型時均返回false:

var name = "Pomy";
name.age = 21;
console.log(name.age); //undefined
console.log(name instanceof String); //false
登入後複製

引用類型:保存為對象,實質是指向記憶體位置的引用,所以不在變數中保存對象。除了自訂的對象,JavaScript提供了6中內建類型:


●Array:數組類型,以數字為索引的一組值的有序列表

●Date:日期和時間類型

● Error:運行期間錯誤型別

●Function:函數型別

●Object:通用物件類型

●RegExp:正規表示式類型

可以用new來實例化每一個對象,或是用字面量形式來建立物件:

var obj = new Object;
var own = {
name:"Pomy",
blog:"http://www.ido321.com",
"my age":22
};
console.log(own.blog); //访问属性
console.log(own["my age"]);
obj = null; //解除引用
登入後複製

obj 並不包含物件實例,而是指向記憶體中實際物件所在位置的指標(或說引用)。因為typeof對所有非函數的參考型別均傳回object,所以需要用instanceof來偵測引用型別。

函數

在JavaScript中,函數就是物件。使函數不同於其他物件的決定性特性是函數存在一個被稱為[[Call]]的內部屬性。內部屬性無法透過程式碼存取而是定義了程式碼執行時的行為。

建立形式

1、函數宣告:用function關鍵字,會被提升至上下文

2、函數表達式:不能被提升 
3、實例化Function內建型別

sayHi(); //函数提升
function sayHi(){
console.log("Hello");
}
//其他等效等效方式
/*
var sayHi = function(){
console.log("Hello");
}
var sayHi = new Function(" console.log(\"Hello\");");
*/
登入後複製

參數

3、實例化Function內建型別

alert(Array.isArray(arguments));   //false
登入後複製

參數

函數的另外一個獨特之處在於可以給函數傳遞任意數量的參數。函數參數被保存在arguments類別數組物件中,其自動存在函數中,能透過數字索引來引用參數,但它不是數組實例:

function ref(value){
return value;
}
console.log(ref("Hi"));
console.log(ref("Hi",22));
console.log(ref.length); //1
登入後複製

類數組物件arguments 保存的是函數的實參,但並不會忽略形參。因而,arguments.length返回實參列表的長度,arguments.callee.length返回形參列表的長度。

var per1 = {
name:"Pomy",
blog:"http://www.ido321.com"
};
var per2 = new Object;
per2.name = "不写代码的码农";
登入後複製

函數中的this

關於this的問題,可參考此文:JavaScript中的this。


javaScript提供了三個方法用於改變this的指向:call、apply和bind。三個函數的第一個參數都是指定this的值,其他參數都作為參數傳遞給函數。

物件

物件是一種參考類型,創建物件常見的兩種方式:Object建構子和物件字面量形式:

per1.age = 0;
per1.sayName = function(){
alert(this.name); //"Pomy"
}
登入後複製

屬性操作

在Java中,可以隨時為物件添加屬性:

//结果是false
if(per1.age){
alert(true)
}else{
alert(false);
}
登入後複製

因而,在偵測物件屬性是否存在時,常犯的一個錯誤是:

console.log("age" in per1); //true
console.log(per1.hasOwnProperty("age")); //true
console.log("toString" in per1); //true
console.log(per1.hasOwnProperty("toString")); //false
登入後複製

per1.age 是存在的,但是其值是0,所以不能滿足if條件。 if判斷中的值是物件、非空字串、非零數字或true時,判斷會評估為真;而當值為一個null、undefined、0、false、NaN或空字串時評估為假。 

因而,偵測屬性是否存在時,有另外的兩種方式:in和hasOwnProperty(),前者會偵測原型屬性和自有(實例)屬性,後者只偵測自有(實例)屬性。

function isPrototypeProperty(obj,name){
return name in obj && !obj.hasOwnProperty(name);
}
登入後複製

物件per1並沒有定義toString,此屬性繼承於Object.prototype,所以in和hasOwnProperty()偵測該屬性時出現差異。如果只想判斷一個物件屬性是不是原型,可以利用以下方法:

per1.toString = function(){
console.log("per1对象");
};
console.log(per1.hasOwnProperty("toString")); //true
per1.toString(); //"per1对象"
delete per1.toString;
console.log(per1.hasOwnProperty("toString")); //false
console.log(per1.toString()); //[object Object]
登入後複製

若要刪除一個屬性,用delete操作符,用於刪除自有屬性,不能刪除原型屬性。

var per3 = {
name:"Pomy",
blog:"http://www.ido321.com",
age:22,
getAge:function(){
return this.age;
}
};
登入後複製

有時需要枚舉物件的可枚舉屬性,也有兩種方式:for-in循環和Object.keys(),前者依舊會遍歷出原型屬性,後者只傳回自有屬性。所有可列舉屬性的內部屬性[[Enumerable]]的值均為true。

console.log(per3.propertyIsEnumerable("name")); //true
var pros = Object.keys(per3); //返回可枚举属性的名字数组
console.log("length" in pros); //true
console.log(pros.propertyIsEnumerable("length")); //false
登入後複製

實際上,大部分原生屬性的[[Enumerable]]的值均為false,即該屬性不能枚舉。可以透過propertyIsEnumerable()來偵測屬性是否可以列舉:

Object.defineProperty(per3,"sex",{
value:"male",
enumerable:false,
configurable:false, //属性不能删除和修改,该值也不能被设置成true
});
console.log(per3.sex); //'male'
console.log(per3.propertyIsEnumerable("sex")); //false
delete per3.sex; //不能删除
per3.sex = "female"; //不能修改
console.log(per3.sex); //'male'
Object.defineProperty(per3,"sex",{
configurable:true, //报错
});
per4 = {};
Object.defineProperties(per4,{
name:{
value:"dwqs",
writable:true
},
blog:{
value:"http://blog.92fenxiang.com"
},
Name:{
get:function(){
return this.name;
},
set:function(value){
this.name = value;
},
enumerable:true,
configurable:true
}
});
console.log(per4.name); //dwqs
per4.Name = "Pomy";
console.log(per4.Name); //Pomy
登入後複製
登入後複製

屬性name是自訂的,可枚舉;屬性length是Array.prototype的內建屬性,不可枚舉。

屬性類型🎜🎜屬性有兩種類型:資料屬性和存取器屬性。二者皆具有四個屬性特徵:🎜

●数据属性:[[Enumerable]]、[[Configurable]]、[[Value]]和[[Writable]]

●访问器属性:[[Enumerable]]、[[Configurable]]、[[Get]]和[[Set]]

[[Enumerable]]:布尔值,属性是否可枚举,自定义属性默认是true。 [[Configurable]]:布尔值,属性是否可配置(可修改或可删除),自定义属性默认是true。它是不可逆的,即设置成false后,再设置成true会报错。

[[Value]]:保存属性的值。

[[Writable]]:布尔值,属性是否可写,所有属性默认可写。
[[Get]]:获取属性值。
[[Set]]:设置属性值。

ES 5提供了两个方法用于设置这些内部属性:

Object.defineProperty(obj,pro,desc_map) 和 Object.defineProperties(obj,pro_map)。利用这两个方法为per3添加一个属性和创建一个新对象per4:

Object.defineProperty(per3,"sex",{
value:"male",
enumerable:false,
configurable:false, //属性不能删除和修改,该值也不能被设置成true
});
console.log(per3.sex); //'male'
console.log(per3.propertyIsEnumerable("sex")); //false
delete per3.sex; //不能删除
per3.sex = "female"; //不能修改
console.log(per3.sex); //'male'
Object.defineProperty(per3,"sex",{
configurable:true, //报错
});
per4 = {};
Object.defineProperties(per4,{
name:{
value:"dwqs",
writable:true
},
blog:{
value:"http://blog.92fenxiang.com"
},
Name:{
get:function(){
return this.name;
},
set:function(value){
this.name = value;
},
enumerable:true,
configurable:true
}
});
console.log(per4.name); //dwqs
per4.Name = "Pomy";
console.log(per4.Name); //Pomy
登入後複製
登入後複製

需要注意的是,通过这两种方式来定义新属性时,如果不指定特征值,则默认是false,也不能创建同时具有数据特征和访问器特征的属性。可以通过Object.getOwnPropertyDescriptor()方法来获取属性特征的描述,接受两个参数:对象和属性名。若属性存在,则返回属性描述对象。

var desc = Object.getOwnPropertyDescriptor(per4,"name");
console.log(desc.enumerable); //false
console.log(desc.configurable); //false
console.log(desc.writable); //true
登入後複製

根据属性的属性类型,返回的属性描述对象包含其对应的四个属性特征。

禁止修改对象

对象和属性一样具有指导其行为的内部特征。其中,[[Extensible]]是一个布尔值,指明改对象本身是否可以被修改([[Extensible]]值为true)。创建的对象默认都是可以扩展的,可以随时添加新的属性。

ES5提供了三种方式:

●Object.preventExtensions(obj):创建不可扩展的obj对象,可以利用Object.isExtensible(obj)来检测obj是否可以扩展。严格模式下给不扩展对象添加属性会报错,非严格模式下则添加失败。

●Object.seal(obj):封印对象,此时obj的属性变成只读,不能添加、改变或删除属性(所有属性都不可配置),其[[Extensible]]值为false,[[Configurable]]值为false。可以利用Object.isSealed(obj)来检测obj是否被封印。

●Object.freeze(obj):冻结对象,不能在冻结对象上添加或删除属性,不能改变属性类型,也不能写入任何数据类型。可以利用Object.isFrozen(obj)来检测obj是否被冻结。


注意:冻结对象和封印对象均要在严格模式下使用。

"use strict";
var per5 = {
name:"Pomy"
};
console.log(Object.isExtensible(per5)); //true
console.log(Object.isSealed(per5)); //false
console.log(Object.isFrozen(per5)); //false
Object.freeze(per5);
console.log(Object.isExtensible(per5)); //false
console.log(Object.isSealed(per5)); //true
console.log(Object.isFrozen(per5)); //true
per5.name="dwqs";
console.log(per5.name); //"Pomy"
per5.Hi = function(){
console.log("Hi");
};
console.log("Hi" in per5); //false
delete per5.name;
console.log(per5.name); //"Pomy"
var desc = Object.getOwnPropertyDescriptor(per5,"name");
console.log(desc.configurable); //false
console.log(desc.writable); //false
登入後複製

注意,禁止修改对象的三个方法只对对象的自有属性有效,对原型对象的属性无效,仍然可以在原型上添加或修改属性。

function Person(name){
this.name = name;
}
var person1 = new Person("Pomy");
var person2 = new Person("dwqs");
Object.freeze(person1);
Person.prototype.Hi = function(){
console.log("Hi");
};
person1.Hi(); //"Hi";
person2.Hi(); //"Hi";
登入後複製

构造函数和原型对象

构造函数也是函数,用new创建对象时调用的函数,与普通函数的一个区别是,其首字母应该大写。但如果将构造函数当作普通函数调用(缺少new关键字),则应该注意this指向的问题。

var name = "Pomy";
function Per(){
console.log("Hello "+this.name);
}
var per1 = new Per(); //"Hello undefined"
var per2 = Per(); //"Hello Pomy"
登入後複製

使用new时,会自动创建this对象,其类型为构造函数类型,指向对象实例;缺少new关键字,this指向全局对象。


可以用instanceof来检测对象类型,同时每个对象在创建时都自动拥有一个constructor属性,指向其构造函数(字面量形式或Object构造函数创建的对象,指向Object,自定义构造函数创建的对象则指向它的构造函数)。

console.log(per1 instanceof Per); //true
console.log(per1.constructor === Per); //true
登入後複製

每个对象实例都有一个内部属性:[[Prototype]],其指向该对象的原型对象。构造函数本身也具有prototype属性指向原型对象。所有创建的对象都共享该原型对象的属性和方法。

function Person(){}
Person.prototype.name="dwqs";
Person.prototype.age=20;
Person.prototype.sayName=function()
{
alert(this.name);
};
var per1 = new Person();
per1.sayName(); //dwqs
var per2 = new Person();
per2.sayName(); //dwqs
alert(per1.sayName == per2.sayName); //true
登入後複製

JavaScript物件導向精要

所以,**实例中的指针仅指向原型,而不指向构造函数。**ES5提供了hasOwnProperty()和isPropertyOf()方法来反应原型对象和实例之间的关系

alert(Person.prototype.isPrototypeOf(per2)); //true
per1.blog = "www.ido321.com";
alert(per1.hasOwnProperty("blog")); //true
alert(Person.prototype.hasOwnProperty("blog")); //false
alert(per1.hasOwnProperty("name")); //false
alert(Person.prototype.hasOwnProperty("name")); //true
登入後複製

因为原型对象的constructor属性是指向构造函数本身,所以在重写原型时,需要注意constructor属性的指向问题。

function Hello(name){
this.name = name;
}
//重写原型
Hello.prototype = {
sayHi:function(){
console.log(this.name);
}
};
var hi = new Hello("Pomy");
console.log(hi instanceof Hello); //true
console.log(hi.constructor === Hello); //false
console.log(hi.constructor === Object); //true
登入後複製

使用对象字面量形式改写原型对象改变了构造函数的属性,因此constructor指向Object,而不是Hello。如果constructor指向很重要,则需要在改写原型对象时手动重置其constructor属性

Hello.prototype = {
constructor:Hello,
sayHi:function(){
console.log(this.name);
}
};
console.log(hi.constructor === Hello); //true
console.log(hi.constructor === Object); //false
登入後複製

利用原型对象的特性,我们可以很方便的在JavaScript的内建原型对象上添加自定义方法:

Array.prototype.sum=function(){
return this.reduce(function(prev,cur){
return prev+cur;
});
};
var num = [1,2,3,4,5,6];
var res = num.sum();
console.log(res); //21
String.prototype.capit = function(){
return this.charAt(0).toUpperCase()+this.substring(1);
};
var msg = "hello world";
console.log(msg.capit()); //"Hello World"
登入後複製

继承

利用[[Prototype]]特性,可以实现原型继承;对于字面量形式的对象,会隐式指定Object.prototype为其[[Prototype]],也可以通过Object.create()显示指定,其接受两个参数:第一个是[[Prototype]]指向的对象(原型对象),第二个是可选的属性描述符对象。

var book = {
title:"这是书名";
};
//和下面的方式一样
var book = Object.create(Object.prototype,{
title:{
configurable:true,
enumerable:true,
value:"这是书名",
wratable:true
}
});
登入後複製

字面量对象会默认继承自Object,更有趣的用法是,在自定义对象之间实现继承。

var book1 = {
title:"JS高级程序设计",
getTitle:function(){
console.log(this.title);
}
};
var book2 = Object.create(book1,{
title:{
configurable:true,
enumerable:true,
value:"JS权威指南",
wratable:true
}
});
book1.getTitle(); //"JS高级程序设计"
book2.getTitle(); //"JS权威指南"
console.log(book1.hasOwnProperty("getTitle")); //true
console.log(book1.isPrototypeOf("book2")); //false
console.log(book2.hasOwnProperty("getTitle")); //false
登入後複製

当访问book2的getTitle属性时,JavaScript引擎会执行一个搜索过程:现在book2的自有属性中寻找,找到则使用,若没有找到,则搜索[[Prototype]],若没有找到,则继续搜索原型对象的[[Prototype]],直到继承链末端。末端通常是Object.prototype,其[[Prototype]]被设置为null。


实现继承的另外一种方式是利用构造函数。每个函数都具有可写的prototype属性,默认被自懂设置为继承自Object.prototype,可以通过改写它来改变原型链。

function Rect(length,width){
this.length = length;
this.width = width;
}
Rect.prototype.getArea = function(){
return this.width * this.length;
};
Rect.prototype.toString = function(){
return "[Rect"+this.length+"*"+this.width+"]";
};
function Square(size){
this.length = size;
this.width = size;
}
//修改prototype属性
Square.prototype = new Rect();
Square.prototype.constructor = Square;
Square.prototype.toString = function(){
return "[Square"+this.length+"*"+this.width+"]";
};
var rect = new Rect(5,10);
var square = new Square(6);
console.log(rect.getArea()); //50
console.log(square.getArea()); //36
登入後複製

如果要访问父类的toString(),可以这样做:

Square.prototype.toString = function(){
var text = Rect.prototype.toString.call(this);
return text.replace("Rect","Square");
}
登入後複製

更多JavaScript物件導向精要相关文章请关注PHP中文网!

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

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1318
25
PHP教程
1269
29
C# 教程
1248
24
WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

如何將 MySQL 查詢結果陣列轉換為物件? 如何將 MySQL 查詢結果陣列轉換為物件? Apr 29, 2024 pm 01:09 PM

將MySQL查詢結果陣列轉換為物件的方法如下:建立一個空物件陣列。循環結果數組並為每一行建立一個新的物件。使用foreach迴圈將每一行的鍵值對賦給新物件的對應屬性。將新物件加入到物件數組中。關閉資料庫連線。

PHP 函數如何傳回物件? PHP 函數如何傳回物件? Apr 10, 2024 pm 03:18 PM

PHP函數可以透過使用return語句後接物件實例來傳回對象,從而將資料封裝到自訂結構中。語法:functionget_object():object{}。這允許創建具有自訂屬性和方法的對象,並以對象的形式處理資料。

如何在JavaScript中取得HTTP狀態碼的簡單方法 如何在JavaScript中取得HTTP狀態碼的簡單方法 Jan 05, 2024 pm 01:37 PM

JavaScript中的HTTP狀態碼取得方法簡介:在進行前端開發中,我們常常需要處理與後端介面的交互,而HTTP狀態碼就是其中非常重要的一部分。了解並取得HTTP狀態碼有助於我們更好地處理介面傳回的資料。本文將介紹使用JavaScript取得HTTP狀態碼的方法,並提供具體程式碼範例。一、什麼是HTTP狀態碼HTTP狀態碼是指當瀏覽器向伺服器發起請求時,服務

C++ 函式回傳物件時有什麼需要注意的? C++ 函式回傳物件時有什麼需要注意的? Apr 19, 2024 pm 12:15 PM

在C++中,函數傳回物件需要注意三點:物件的生命週期由呼叫者負責管理,以防止記憶體洩漏。避免懸垂指針,透過動態分配記憶體或返回物件本身來確保物件在函數返回後仍然有效。編譯器可能會最佳化傳回物件的副本生成,以提高效能,但如果物件是值語義傳遞的,則無需副本生成。

分析Java中堆疊和堆疊的不同以及它們的應用情景 分析Java中堆疊和堆疊的不同以及它們的應用情景 Feb 24, 2024 pm 11:12 PM

Java堆和棧的區別及應用場景解析,需要具體程式碼範例在Java程式中,堆和棧是兩個常用的資料結構,它們在記憶體中承擔不同的角色和功能。了解堆疊和堆疊的差異對於編寫高效的Java程式至關重要。首先,我們來看看Java堆。堆是一個用來儲存物件的區域,所有在程式中被建立的物件都被儲存在堆中。堆是在程式運行時動態分配和釋放記憶體的地方,它不受任何限制,並且可以根據需要自動

See all articles