1.創(chuàng)建對(duì)象(兩種)
(1)//普通創(chuàng)建
var person = new Object();
// var person = {}//簡(jiǎn)寫(xiě)
//函數(shù)封裝--工廠(chǎng)方式
function createPerson(name) {
//特點(diǎn):流水線(xiàn)生產(chǎn)
//原材料
var person = new Object();
//加工
person.name = name;
person.showName = function () {
console.log(this.name)
}
//出產(chǎn)品
return person;//返回對(duì)象,否則無(wú)法創(chuàng)建擎厢,為undefine
}
var p1 = createPerson("huahua");//封裝方式的創(chuàng)建
p1.showName();打印
(2)//new方法創(chuàng)建即構(gòu)造函數(shù)創(chuàng)建
new關(guān)鍵字作用
/**
1.創(chuàng)建一個(gè)新對(duì)象
2.將構(gòu)造函數(shù)的作用域賦給新對(duì)象(因此究流,this就指向了這個(gè)新對(duì)象)
3.指向鉤子函數(shù)中的代碼(為這個(gè)新對(duì)象添加屬性)
4.返回新對(duì)象(不用寫(xiě)return)
*/
//改寫(xiě)如下
//構(gòu)造函數(shù)無(wú)返回值
function CreatePerson(name){
this.name = name
this.showName = function(){
alert(this.name)
}
}
2.對(duì)象引用
//基本類(lèi)型
var num1 = 20;
var num2 = num1;
console.log(num1)//20
//引用類(lèi)型
var arr1 = [1, 2, 3];
var arr2 = arr1;
arr2.push(4);
console.log(arr1)//[1,2,3,4]發(fā)生了改變
如果從一個(gè)變量向另一個(gè)變量復(fù)制引用類(lèi)型的值,同樣還是會(huì)將存儲(chǔ)在變量對(duì)象中的值復(fù)制一份放到新變量分配的空間中动遭,不同的是芬探,復(fù)制的這個(gè)副本是一個(gè)指針,并不是具體的對(duì)象厘惦,這個(gè)指針指向存儲(chǔ)在堆內(nèi)存中的一個(gè)對(duì)象偷仿,復(fù)制操作結(jié)束后,兩個(gè)變量實(shí)際上將引用同一個(gè)對(duì)象
3.原型(prototype)的使用
我們創(chuàng)建的每一個(gè)函數(shù)都有一個(gè)prototype(原型)屬性宵蕉,這個(gè)屬性是一個(gè)指針酝静,指向一個(gè)對(duì)象,而這個(gè)對(duì)象的用途是包含可以由特定類(lèi)型的所有實(shí)例共享的屬性和方法羡玛,這個(gè)對(duì)象就是構(gòu)造函數(shù)CreatePerson的原型對(duì)象别智,當(dāng)調(diào)用CreatePerson創(chuàng)建出一個(gè)具體對(duì)象p1后,p1內(nèi)部也有一個(gè)指針指向構(gòu)造函數(shù)的原型對(duì)象稼稿,同樣的道理亿遂,不管創(chuàng)建出多少對(duì)象,這些對(duì)象內(nèi)部都會(huì)有個(gè)指針執(zhí)行構(gòu)造函數(shù)的原型對(duì)象渺杉,使用原型對(duì)象的好處是讓所有被創(chuàng)建出來(lái)的對(duì)象共享這個(gè)原型對(duì)象所包含的屬性和方法
function CreatePerson(name){
this.name = name
}
// 每個(gè)函數(shù)都有一個(gè)prototype對(duì)象,即指針(對(duì)象的指針指向prototype對(duì)象的地址)挪钓,指向一個(gè)對(duì)象(原型對(duì)象)
//創(chuàng)建出來(lái)的對(duì)象是越,也指向原型對(duì)象
CreatePerson.prototype.showName = function(){
alert(this.name)
}
var p1 = new CreatePerson("小強(qiáng)")
var p2 = new CreatePerson("小花")
var p3 = new CreatePerson("小豆")
alert(p1.showName === p2.showName) // true
alert(p2.showName === p3.showName) // true
// 錯(cuò)誤演示
console.log(p1.prototype)//undeifined,原型是在構(gòu)造函數(shù)上的且不可見(jiàn)的!!!
//瀏覽器產(chǎn)商 Chrome firefox自己實(shí)現(xiàn)了prototype可見(jiàn),但不是標(biāo)準(zhǔn)B瞪稀倚评!!
有些瀏覽器沒(méi)得
console.log(p1.__proto__);//下劃線(xiàn)左右兩個(gè),p1.__proto__指向原型對(duì)象
面向?qū)ο筮x項(xiàng)卡:
//面向過(guò)程版的:
var oWrap = document.getElementById("wrap");
var aBtn = oWrap.getElementsByTagName("button")
var aDiv = oWrap.getElementsByTagName("div")
for(var i=0; i<aBtn.length;i++){
aBtn[i].index = i
aBtn[i].onmouseover = function () {
for(var j=0;j<aBtn.length;j++){
aBtn[j].style.backgroundColor = "white"
aDiv[j].style.display = "none"
}
this.style.backgroundColor = "orangered"
aDiv[this.index].style.display = "block"
}
}
//面向?qū)ο蟀娴模?/1./把面向過(guò)程的代碼整理浦徊,功能封裝
// 2.面向?qū)ο笸晟?// (1).全局變量就是屬性 (2).函數(shù)就是方法(3).既不是全局和函數(shù),就封裝成初始化方法
//3天梧、調(diào)整this指向(出現(xiàn)嵌套代碼塊盔性,一般this指向不同)
//id用來(lái)代表多個(gè)選項(xiàng)卡中選中的一個(gè)
function Tab(id) {
this.oWrap = document.getElementById(id);
this.aBtn = this.oWrap.getElementsByTagName("button");
this.aDiv = this.oWrap.getElementsByTagName("div");
}
//記得加this,指向
Tab.prototype.changeTab = function (obj) {
for(var j=0;j<this.aBtn.length;j++){
this.aBtn[j].style.backgroundColor = "white"
this.aDiv[j].style.display = "none"
}
obj.style.backgroundColor = "orangered"
this.aDiv[obj.index].style.display = "block"
}
//初始化方法
Tab.prototype.init = function () {
var That = this
for(var i=0; i<this.aBtn.length;i++){
this.aBtn[i].index = i;
console.log("外層",this)
this.aBtn[i].onmouseover = function () {
That.changeTab(this)
console.log("內(nèi)層",this)
}
}
}
//創(chuàng)建對(duì)象呢岗,調(diào)用
var t1 = new Tab("wrap")
t1.init()
var t2 = new Tab("wrap2")
t2.init()
3.包裝對(duì)象
字符串為啥可以使用:charAt冕香、indexOf、replace等方法后豫?
-----基本類(lèi)型都有其對(duì)應(yīng)的一個(gè)包裝對(duì)象悉尾,例如:字符串類(lèi)型對(duì)應(yīng)的包裝對(duì)象是String,數(shù)字的包裝對(duì)象是Number挫酿,布爾類(lèi)型對(duì)應(yīng)的包裝對(duì)象是Boolean构眯。根據(jù)原型知識(shí),我們可以猜測(cè)一下charAt可能是掛載到String構(gòu)造函數(shù)原型上的早龟,所以當(dāng)str對(duì)象去調(diào)用charAt方法是可以正常運(yùn)行的
String.prototype.charAt = function(){}
//給String構(gòu)造函數(shù)自定義一個(gè)方法惫霸,看普通的字符串是否也能夠使用
//創(chuàng)建一個(gè)字符串對(duì)象
var str1 = new String("hello")
String.prototype.test = function(){
alert(1)
}
//創(chuàng)建一個(gè)基本類(lèi)型字符串
var str2 = "hello2"
str2.test() // 彈出1
//如果給str2掛載一個(gè)屬性,看看效果
str2.num = 10
alert(str2.num) // undefined
//從上面的代碼我們知道了 基本類(lèi)型的str2可以使用方法葱弟,實(shí)際上使用的是String身上的方法
上面代碼實(shí)際上執(zhí)行了以下幾個(gè)步驟:
1.創(chuàng)建String 類(lèi)型的對(duì)象
2.在對(duì)象上調(diào)用指定的方法
3.銷(xiāo)毀這個(gè)對(duì)象
4.原型鏈:
原型鏈就是實(shí)例對(duì)象和原型之間的鏈接壹店。每個(gè)函數(shù)都有一個(gè)prototype屬性,這個(gè)prototype指向一個(gè)對(duì)象(利用包裝對(duì)象.prototype.方法名 = function(){}創(chuàng)建的方法)翘悉,這個(gè)對(duì)象叫做原型茫打,通過(guò)構(gòu)造函數(shù)創(chuàng)建出來(lái)的實(shí)例也有一個(gè)內(nèi)部指針指向原型,這樣就形成實(shí)例對(duì)象和原型直接的鏈接妖混,我們把這個(gè)鏈接稱(chēng)為原型鏈老赤。
原型鏈的層級(jí)關(guān)系
原型鏈有多層,最外層為Object.prototype
function Fn1(){
this.num = 10;
}
Fn1.prototype.num = 20
Object.prototype.num = 30
var f1 = new Fn1()
console.log(f1.__proto__)
console.log(f1.__proto__.__proto__.num) //30
-------------------------------------------------------------------------------------------------
//es6 中獲取原型制市,取代__proto__的方法Object.getPrototypeOf(對(duì)象實(shí)例)
console.log(Object.getPrototypeOf(f1) === f1.__proto__);//true
//注意:prototype 是在構(gòu)造函數(shù)上抬旺,__proto__在對(duì)象上
//訪(fǎng)問(wèn)屬性的優(yōu)先級(jí)---就近原則,例如:f1祥楣,F(xiàn)n.prototype, Object.prototype上都有num屬性开财,
//那么alert(f1.num)的時(shí)候,首先取出的是f1身上的值误褪,如果f1身上沒(méi)有责鳍,那么才訪(fǎng)問(wèn)Fn.prototype,
//以此類(lèi)推,訪(fǎng)問(wèn)到最外層Object.prototype兽间,如果最終都沒(méi)有就返回undefined
alert(f1.num)
5.面向?qū)ο蟮南嚓P(guān)屬性和方法
//hasOwnProperty
function Fn() {
this.name = 20;
}
Fn.prototype.age = 40;
var f1 = new Fn();
alert(f1.hasOwnProperty("name"))//true
alert(f1.hasOwnProperty("age"))//false
alert(Fn.hasOwnProperty("name"))//true
//constructor
console.log(f1.constructor)//查看該對(duì)象的構(gòu)造函數(shù)
console.log(Fn.prototype.constructor)
function Fn1(){}
// 指向Fn1的
Fn1.prototype.name = 10
Fn1.prototype.age = 20
// 指向Object的历葛,把一個(gè)對(duì)象賦值給原型對(duì)象,被后面的對(duì)象覆蓋了
Fn1.prototype = {
name: 10,
age: 20
}
// 指向Object
console.log(Fn1.prototype.constructor)
// 當(dāng)一個(gè)構(gòu)造函數(shù)新創(chuàng)建出來(lái)后嘀略,會(huì)自動(dòng)生成下面一句話(huà)
Fn1.prototype.constructor = Fn1
// 上面的寫(xiě)法不經(jīng)意間就會(huì)把constructor修改掉,因此,我們需要手動(dòng)去修正
function Fn1(){}
Fn1.prototype = {
constructor: Fn1,
name: 10,
age: 20
}
// 指向Fn1
console.log(Fn1.prototype.constructor)
//自己添加的num屬性是可以被打印出來(lái)的最域,系統(tǒng)自帶的沒(méi)辦法for in循環(huán)出來(lái)
Fn1.prototype.num = 10
for(var attr in Fn1.prototype){
console.log(attr) //把constructor name age num屬性打印了一遍,沒(méi)打印值
}
//instanceof 用來(lái)測(cè)試一個(gè)對(duì)象在其原型鏈中是否存在一個(gè)構(gòu)造函數(shù)的 prototype 屬性
alert(f1 instanceof Fn1) //true
alert(f1 instanceof Array) //false
//toString()
// toStringtoString的作用是把對(duì)象轉(zhuǎn)換成字符串鸠天,如果是系統(tǒng)自帶的對(duì)象去調(diào)用toString方法, 那么toString方法在原型對(duì)象上帐姻,如果不是系統(tǒng)自帶的對(duì)象去調(diào)用toString方法稠集,那么toString在Object.prototype上
var arr =[1,2,3]
// 調(diào)用的是Array.prototype原型對(duì)象上的toString();
console.log(arr.toString())
console.log(f1)//toSting()在Object上
// 改寫(xiě)應(yīng)用與分割字符
Array.prototype.toString = function () {
return this.join("-")
}
console.log(arr.toString())
//轉(zhuǎn)換16進(jìn)制顏色
var num1 = 255;
console.log(num1.toString(16))//打印ff
//判斷類(lèi)型(推薦第三種)
// 判斷類(lèi)型方法 consructor instanceof toString
var arr=[]
console.log(arr.constructor == Array)//true
console.log(arr.prototype)//undefined
console.log(arr.prototype instanceof Array)//false
console.log(arr instanceof Array)//true
console.log(arr.toString() === Array)//false
// //call(對(duì)象)改變內(nèi)部this指向,應(yīng)用某一對(duì)象的一個(gè)方法卖宠,用另一個(gè)對(duì)象替換當(dāng)前對(duì)象
console.log(Object.prototype.toString.call(arr))//[object Array]
console.log(Object.prototype.toString.call())//[object Undefined] 因?yàn)闆](méi)有傳入
console.log(Object.prototype.toLocaleString.call(arr))//1-2-3
6.call()方法和apply()方法巍杈。都是調(diào)用一個(gè)對(duì)象的一個(gè)方法,以另一個(gè)對(duì)象替換當(dāng)前對(duì)象扛伍,可以理解為借用一個(gè)對(duì)象的方法筷畦。傳參形式不同!
function Fn1(){
}
function Fn2(){
}
Fn1.prototype.showAge = function (age,age2) {
alert(age)
alert(age2)
}
var f1 = new Fn1()
var f2 = new Fn2()
f1.showAge(20);
f1.showAge.apply(f2)//undefind
f1.showAge.call(f2,20,63)//多個(gè)分隔開(kāi)
f1.showAge.apply(f2,[20,23])//可傳多個(gè)參數(shù),多個(gè)用數(shù)組
7.繼承
function Parent(name, age) {
this.name = name;
this.age = age;
}
Parent.prototype.showName = function () {
alert(this.name)
};
function Child(name, age) {
//Parent里面的this指向會(huì)出現(xiàn)問(wèn)題刺洒,直接調(diào)用Parent()函數(shù)鳖宾,相當(dāng)于window.Parent(),那么函數(shù)里面的this是指向window的,這個(gè)時(shí)候逆航,我們需要修正Parent里面的this鼎文,讓Parent里面的this指向Child才行
//Parent.call(name, age)
//不能具體指明對(duì)象,new的對(duì)象因俐,很多且不同
Parent.call(this, name, age)
}
//繼承方法拇惋,把Parent的原型賦值給Child原型
//對(duì)象引用,兩個(gè)對(duì)象指向同一個(gè)地址抹剩,撑帖,任何一個(gè)對(duì)象的修改都會(huì)影響另一個(gè)對(duì)象
// Child.prototype = Parent.prototype;
//影響:父中和子中都有同樣的方法。解決如下:
function extend(obj1,obj2){
//循環(huán)obj2的內(nèi)容澳眷,賦給obj1胡嘿。for in專(zhuān)門(mén)循環(huán)對(duì)象
for (var attr in obj2) {
obj1[attr] = obj2[attr]
}
}
//封裝extend方法的原因,直接對(duì)象賦值給對(duì)象的話(huà)钳踊,會(huì)造成對(duì)象的引用衷敌,兩者相互影響
Child.prototype.showAge = function () {
alert(this.age)
};
var c1 = new Child("小紅", 222)
c1.showName()
c1.showAge()