javascript
JavaScript高级学习(三)
一. 原型和原型鏈
實例對象中的__proto__原型指向的是構造函數中的原型prototype
consolg.log(per.__proto__==Person.prptptype);//true
實例對象可以直接訪問原型對象中的屬性或者方法。
原型鏈:實例對象和原型對象之間的關系,是通過原型(__proto__)來聯系的。
二. 原型指向
原型指向是否可以改變?——可以
構造函數中的this就是實例對象
原型對象的方法中的this就是實例對象
1.原型指向的改變:
實例對象的原型__proto__指向的是該對象所在的構造函數的原型對象prototype,構造函數的的原型對象prototype指向如果改變了,實例對象的原型__proto__之象也會改變。
stu可以調用eat(),不可以調用sayHi()
原型的指向是可以改變的
實例對象和原型對象之間的關系是通過__proto__原型來聯系起來的,這個關系就是原型鏈。
2.原型的最終指向
實例對象中有__proto__原型
構造函數中有prototype原型
prototype是對象,所以prototype對象也有__proto__---->指向哪里?
實例對象中的__proto__----->構造函數的prototype
所以,prototype這個對象的__proto__之鄉的應該是某個構造函數的原型prototype。
以這個代碼為例:
function Person() {}Person.prototype.eat=function () {console.log("吃東西");};var per=new Person();console.dir(per);console.dir(Person);stu.proto----->Person.prototype
Person.prototype.proto----->Object.prototype
Object.prototype.proto------>null
3.原型指向改變如何添加方法?
原型改變指向有兩種順序:
①先方法后指向
原型指向改變,不再指向含有sayHi()的原型,所以無法訪問sayHi()
②先改指向后添方法
由于先改變指向,再添加方法,所以sayHi()添加到了改變指向后的“實例對象”中。
先改變指向后添加方法可以訪問到相應的方法
4.實例對象和原型對象屬性重名問題
function Person(age,sex) {this.age=age;this.sex=sex;}Person.prototype.sex="女";var per=new Person(10,"男");console.log(per.sex);//男實例對象訪問sex屬性,應該先從實例對象中找,找到了直接用,找不到的時候就去指向的原型對象中找,找到了就使用,找不到…?
console.log(per.fdsfdsfsdfds);//undefined因為JS是一門動態語言,當一個對象沒有一個東西時時,只要點了,那么這個對象就有了這個東西;當沒有這個屬性時,只要對象.屬性名字,對象就有這個屬性了,但是,該屬性沒有賦值,所以,結果是:undefined
console.log(fsdfdsfds);//報錯沒有fsdfdsfds這么變量
5.一個指向的例子
<div id="dv"></div> <script>var divObj=document.getElementById("dv");console.dir(divObj);</script>我們可以看到div的結構,然后查看他的指向
divObj.proto---->HTMLDivElement.prototype的__proto__—>HTMLElement.prototype的__proto__---->Element.prototype的__proto__---->Node.prototype的__proto__---->EventTarget.prototype的__proto__---->Object.prototype沒有__proto__,所以,Object.prototype中的__proto__是null
繼承
面向對象編程思想:
??????根據需求,分析對象,找到對象的特征和行為,通過代碼的形式實現需求,要想實現需求,就要創建對象:構造函數------創建對象,通過調用屬性和方法來實現相應的功能及需求。
JS不是面向對象語言,而是基于對象的語言。-------為什么學習面向對象?
??????面向對象思想更適合人的思想,編程起來更加的方便,及后期的維護。
面向對象的特征:
- 封裝:就是包裝
一個值存儲再一個變量中------封裝
一段重復代碼放在一個函數中-------封裝
… - 多態
一個對象有不同的行為,或者是同一個行為針對不同的對象,產生不同的結果
要想有多態,就要有繼承,JS可以模擬多態,但是不會使用 - 繼承
是一種關系,類與類之間的關系,JS通過構造函數模擬類,通過原型實現繼承
繼承是為了多態服務,JS的繼承也是為了實現數據共享。
原型的作用:
- 數據共享,節省內存空間
- 為了實現繼承
繼承是一種關系,父類級別和類級別的關系。
1.改變原型指向:
Student.prototype=new Person("小明“,10,"男");例子:
//動物的構造韓素function Animal(name,weight) {this.name=name;this.weight=weight;}//動物的原型的方法Animal.prototype.eat=function () {console.log("天天吃東西,就是吃");};//狗的構造函數function Dog(color) {this.color=color;}Dog.prototype=new Animal("哮天犬","50kg");Dog.prototype.bitePerson=function () {console.log("哼~汪汪~咬死你");};//哈士奇function ErHa(sex) {this.sex=sex;}ErHa.prototype=new Dog("黑白色");ErHa.prototype.playHost=function () {console.log("哈哈~要壞衣服,要壞桌子,拆家..嘎嘎...好玩,開心不,驚喜不,意外不");};var erHa=new ErHa("雄性");console.log(erHa.name,erHa.weight,erHa.color);erHa.eat();erHa.bitePerson();erHa.playHost();
2.借用構造函數
我們來看下下面的例子
function Person(name,age,sex,weight) {this.name=name;this.age=age;this.sex=sex;this.weight=weight;}Person.prototype.sayHi=function () {console.log("您好");};function Student(score) {this.score=score;}//希望人的類別中的數據可以共享給學生---繼承Student.prototype=new Person("小明",10,"男","50kg");var stu1=new Student("100");console.log(stu1.name,stu1.age,stu1.sex,stu1.weight,stu1.score);stu1.sayHi();以上代碼實現了繼承,實例對象stu1繼承了Person的屬性和方法,但是,之后創建的所有實例對象的屬性值都是一樣的
為了數據共享,改變原型指向,做到了繼承
①缺陷:因為改變原型指向的同時實現了繼承,直接初始化了屬性,繼承過來的屬性值都是一樣的--------問題
重新調用對象的屬性進行賦值可以解決這個問題,但是這樣會增加代碼,太過繁瑣。
②解決方案:繼承的時候,不用改變原型的指向,直接調用父級的構造函數的方式來為屬性賦值--------借用構造函數(把要繼承的父級的構造函數拿出來,使用一下)
function Person(name, age, sex, weight) {this.name = name;this.age = age;this.sex = sex;this.weight = weight;}Person.prototype.sayHi = function () {console.log("您好");};function Student(name,age,sex,weight,score) {//借用構造函數Person.call(this,name,age,sex,weight);this.score = score;}var stu1 = new Student("小明",10,"男","10kg","100");console.log(stu1.name, stu1.age, stu1.sex, stu1.weight, stu1.score);var stu2 = new Student("小紅",20,"女","20kg","120");console.log(stu2.name, stu2.age, stu2.sex, stu2.weight, stu2.score);var stu3 = new Student("小麗",30,"妖","30kg","130");console.log(stu3.name, stu3.age, stu3.sex, stu3.weight, stu3.score);
借用構造函數:
- 構造函數名字.call(當前對象,屬性1,屬性2…)
- 解決屬性繼承,并且值不重復的問題;
- 缺陷:父級類別中的方法不能繼承。
3.組合繼承
為了解決借用構造函數實現繼承所帶來的問題(父級類別中的方法不能繼承),我們采用組合繼承來實現繼承---------原型繼承+借用構造函數繼承。
4.拷貝繼承
拷貝繼承:把一個對象中的屬性或者方法直接復制到另一個對象中
5.繼承的總結
- 面向對象的特性:封裝、繼承、多態
- 繼承:類與類之間的關系,面向對象語言的繼承是為了多態服務的。JS不是面向對象語言,但是可以模擬面向對象,模擬繼承,為了節省空間。
- 繼承
①原型作用:數據共享;目的:節省空間
??????????????????????繼承;目的:節省空間
②原型繼承:改變原型指向
③借用構造函數繼承:主要解決屬性值相同的問題(Person.call(this,name,age))
④組合繼承:原型繼承+借用構造函數繼承
??????????????????????既能解決屬性值相等的問題,又能解決父級方法調用問題
⑤拷貝繼承:就是把對象中需要共享的屬性或者方法,直接遍歷的方式復制
??????????????????????到另一個對象中
其他知識點
1.逆推繼承看原型
function F1(age) {this.age = age;}function F2(age) {this.age = age;}F2.prototype = new F1(10);function F3(age) {this.age = age;}F3.prototype = new F2(20);var f3 = new F3(30);console.log(f3.age);//30
f3.age先在實例對象中查找,若找不到,則逐級向上查找(原型中),假若原型中也沒有,為undefined
2.函數角色
函數角色:函數聲明、函數表達式
- 函數聲明
- 函數表達式
- 函數聲明和函數表達式的區別
函數聲明如果放在if-else語句中,在IE8的瀏覽器中會出現問題;函數表達式則不會出現問題。
3.函數中this指向問題
- 普通函數中的this-------window
- 對象方法中的this-------當前的實例對象
- 定時器方法中的this-------window
- 構造函數中的this-------實例對象
- 原型對象中的this--------實例對象
4.嚴格模式
嚴格模式下,方法應由對象調用
5.函數的不同調用方法
- 普通函數
- 構造函數
- 對象的方法
6.函數也是對象,對象不一定是函數
對象中有__proto__原型,是對象
函數中有prototype原型,是對象
對象中有__proto__,函數中應該有prototype
如果一個東西里面有prototype,又有__proto__,說明是函數,也是對象
所有的函數實際上都是Function的構造函數創建出來的實例對象====>函數也是對象
Math中有__proto__,但是沒有prorotype,所以Math是對象,但不是函數====>對象不一定是函數
7.數組中的函數調用
數組可以存儲任何類型的數據
var arr=[function () {console.log("十一假期快樂");},function () {console.log("十一假期開心");},function () {console.log("十一假期健康");},function () {console.log("十一假期安全");},function () {console.log("十一假期如意");}];//回調函數:函數作為參數使用arr.forEach(function(ele){ele();});forEach() 方法用于調用數組的每個元素,并將元素傳遞給回調函數。
注意: forEach() 對于空數組是不會執行回調函數的。
array.forEach(function(currentValue, index, arr), thisValue)
總結
以上是生活随笔為你收集整理的JavaScript高级学习(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【P3369 普通平衡树】 Splay
- 下一篇: 《实况足球10》全套数值能力解析