當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
前端学习从入门到高级全程记录之31(JavaScript高级3)
生活随笔
收集整理的這篇文章主要介紹了
前端学习从入门到高级全程记录之31(JavaScript高级3)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
學習目標
本期我們繼續學習JavaScript高級的知識,其中會涉及到繼承這個非常重要的知識點。
1.原型及原型鏈
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>//使用對象---->使用對象中的屬性和對象中的方法,使用對象就要先有構造函數//構造函數function Person(name,age) {//屬性this.name=name;this.age=age;//在構造函數中的方法this.eat=function () {console.log("吃好吃的");};}//添加共享的屬性Person.prototype.sex="男";//添加共享的方法Person.prototype.sayHi=function () {console.log("您好啊,怎么這么帥,就是這么帥");};//實例化對象,并初始化var per=new Person("小明",20);per.sayHi();//如果想要使用一些屬性和方法,并且屬性的值在每個對象中都是一樣的,方法在每個對象中的操作也都是一樣,那么,為了共享數據,節省內存空間,是可以把屬性和方法通過原型的方式進行賦值console.dir(per);//實例對象的結構console.dir(Person);//構造函數的結構//實例對象的原型__proto__和構造函數的原型prototype指向是相同的//實例對象中的__proto__原型指向的是構造函數中的原型prototypeconsole.log(per.__proto__==Person.prototype);//實例對象中__proto__是原型,瀏覽器使用的//構造函數中的prototype是原型,程序員使用的//原型鏈:是一種關系,實例對象和原型對象之間的關系,關系是通過原型(__proto__)來聯系的</script> </head> <body></body> </html>2.原型指向可以改變
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>//構造函數中的this就是實例對象//原型對象中方法中的this就是實例對象 // function Person(age) { // this.age=age; // console.log(this); // } // Person.prototype.eat=function () { // console.log(this); // console.log("您吃了沒,走著,吃點臭豆腐去"); // }; // var per=new Person(10); // per.eat(); // console.log(per);// function Student() { // // } // Student.prototype.study=function () { // console.log("就是天天學習,學習如何做人,如何敲代碼,如何成為人"); // }; // Student.prototype={ // eat:function () { // console.log("哈哈,好吃的榴蓮酥"); // } // }; // // var stu=new Student(); // // stu.eat();//人的構造函數function Person(age) {this.age=10;}//人的原型對象方法Person.prototype.eat=function () {console.log("人的吃");};//學生的構造函數function Student() {}Student.prototype.sayHi=function () {console.log("嗨,小蘇你好帥哦");};//學生的原型,指向了一個人的實例對象Student.prototype=new Person(10);var stu=new Student();stu.eat();stu.sayHi();//原型指向可以改變//實例對象的原型__proto__指向的是該對象所在的構造函數的原型對象//構造函數的原型對象(prototype)指向如果改變了,實例對象的原型(__proto__)指向也會發生改變//原型的指向是可以改變的//實例對象和原型對象之間的關系是通過__proto__原型來聯系起來的,這個關系就是原型鏈</script> </head> <body></body> </html>原型鏈指向改變:
3.原型鏈最終的指向
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>function Person() {}Person.prototype.eat=function () {console.log("吃東西");};var per=new Person();console.dir(per);console.dir(Person);//實例對象中有__proto__原型//構造函數中有prototype原型//prototype是對象//所以,prototype這個對象中也有__proto__,那么指向了哪里//實例對象中的__proto__指向的是構造函數的prototype//所以,prototype這個對象中__proto__指向的應該是某個構造函數的原型prototype//Person的prototype中的__proto__的指向//console.log(Person.prototype.__proto__);//per實例對象的__proto__------->Person.prototype的__proto__---->Object.prototype的__proto__是nullconsole.log(per.__proto__==Person.prototype);console.log(per.__proto__.__proto__==Person.prototype.__proto__);console.log(Person.prototype.__proto__==Object.prototype);console.log(Object.prototype.__proto__);</script> </head> <body></body> </html>4.原型指向改變如何添加方法
<!doctype html> <html lang="en"> <head><meta charset="UTF-8"><title>Document</title> </head> <body> <script>//人的構造函數function Person(age) {this.age = age;}//人的原型中添加方法person.prototype.eat =function () {console.log("人正在吃東西");};//學生構造函數function Student(sex) {this.sex=sex;}//先在學生的原型中添加方法Student.prototype.sayHi=function () {console.log("您好");};//改變了原型對象的指向Student.prototype=new Person(10);var stu=new Student("男");stu.sayHi();//因為指向改變,所以不能訪問stu.eat();//能訪問 </script> </body> </html>但是我就想訪問sayHi方法,該怎么辦呢?
<!doctype html> <html lang="en"> <head><meta charset="UTF-8"><title>Document</title> </head> <body> <script>//人的構造函數function Person(age) {this.age = age;}//人的原型中添加方法person.prototype.eat =function () {console.log("人正在吃東西");};//學生構造函數function Student(sex) {this.sex=sex;}//先改變了原型對象的指向Student.prototype=new Person(10);//再在學生的原型中添加方法Student.prototype.sayHi=function () {console.log("您好");};var stu=new Student("男");stu.sayHi();//能訪問stu.eat();//能訪問 </script> </body> </html>5.實例對象和原型對象屬性重名問題
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>function Person(age,sex) {this.age=age;this.sex=sex;}Person.prototype.sex="女";var per=new Person(10,"男");console.log(per.sex);//因為JS是一門動態類型的語言,對象沒有什么,只要點了,那么這個對象就有了這個東西,沒有這個屬性,只要對象.屬性名字,對象就有這個屬性了,但是,該屬性沒有賦值,所以,結果是:undefinedconsole.log(per.fdsfdsfsdfds);console.log(fsdfdsfds);//實例對象訪問這個屬性,應該先從實例對象中找,找到了就直接用,找不到就去指向的原型對象中找,找到了就使用,找不到呢?=====//通過實例對象能否改變原型對象中的屬性值?不能//就想改變原型對象中屬性的值,怎么辦?直接通過原型對象.屬性=值;可以改變 // Person.prototype.sex="哦嘜嘎的"; // per.sex="人"; // console.log(per.sex); // // console.dir(per);</script> </head> <body></body> </html>6.原型鏈的最終指向
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>//原型鏈:實例對象和原型對象之間的關系,通過__proto__來聯系</script> </head> <body> <div id="dv"></div> <script>var divObj=document.getElementById("dv");console.dir(divObj);//divObj.__proto__---->HTMLDivElement.prototype的__proto__--->HTMLElement.prototype的__proto__---->Element.prototype的__proto__---->Node.prototype的__proto__---->EventTarget.prototype的__proto__---->Object.prototype沒有__proto__,所以,Object.prototype中的__proto__是null</script> </body> </html>
所以你會發現最終的指向是Object,而Object.prototype中的__proto__是null。
7.繼承
7.1 什么是繼承
- 現實生活中的繼承就是繼承父親的財產
- 程序中的繼承類似現實中的繼承
7.2 第一種繼承方式:原型繼承
function Person (name, age) {this.type = 'human'this.name = namethis.age = age }Person.prototype.sayName = function () {console.log('hello ' + this.name) }function Student (name, age) {Person.call(this, name, age) }// 利用原型的特性實現繼承 Student.prototype = new Person()var s1 = Student('張三', 18)console.log(s1.type) // => humans1.sayName() // => hello 張三原型繼承例子:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>//動物有名字,有體重,有吃東西的行為//小狗有名字,有體重,有毛色, 有吃東西的行為,還有咬人的行為//哈士奇名字,有體重,有毛色,性別, 有吃東西的行為,還有咬人的行為,逗主人開心的行為//動物的構造韓素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();</script> </head> <body></body> </html>圖解:
7.3 構造函數的屬性繼承:借用構造函數
function Person (name, age) {this.type = 'human'this.name = namethis.age = age }function Student (name, age) {// 借用構造函數繼承屬性成員Person.call(this, name, age) }var s1 = Student('張三', 18) console.log(s1.type, s1.name, s1.age) // => human 張三 18例子:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>// 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();//// var stu2=new Student("120");// stu2.name="張三";// stu2.age=20;// stu2.sex="女";// console.log(stu2.name,stu2.age,stu2.sex,stu2.weight,stu2.score);// stu2.sayHi();// var stu3=new Student("130");// console.log(stu3.name,stu3.age,stu3.sex,stu3.weight,stu3.score);// stu3.sayHi();//為了數據共享,改變原型指向,做到了繼承---通過改變原型指向實現的繼承//缺陷:因為改變原型指向的同時實現繼承,直接初始化了屬性,繼承過來的屬性的值都是一樣的了,所以,這就是問題//只能重新調用對象的屬性進行重新賦值,//解決方案:繼承的時候,不用改變原型的指向,直接調用父級的構造函數的方式來為屬性賦值就可以了------借用構造函數:把要繼承的父級的構造函數拿過來,使用一下就可以了//借用構造函數:構造函數名字.call(當前對象,屬性,屬性,屬性....);//解決了屬性繼承,并且值不重復的問題//缺陷:父級類別中的方法不能繼承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);</script> </head> <body></body> </html>7.4 組合繼承
解決借用繼承的父類方法無法繼承的問題。
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>//原型實現繼承//借用構造函數實現繼承//組合繼承:原型繼承+借用構造函數繼承function Person(name,age,sex) {this.name=name;this.age=age;this.sex=sex;}Person.prototype.sayHi=function () {console.log("阿涅哈斯誒呦");};function Student(name,age,sex,score) {//借用構造函數:屬性值重復的問題Person.call(this,name,age,sex);this.score=score;}//改變原型指向----繼承Student.prototype=new Person();//不傳值Student.prototype.eat=function () {console.log("吃東西");};var stu=new Student("小黑",20,"男","100分");console.log(stu.name,stu.age,stu.sex,stu.score);stu.sayHi();stu.eat();var stu2=new Student("小黑黑",200,"男人","1010分");console.log(stu2.name,stu2.age,stu2.sex,stu2.score);stu2.sayHi();stu2.eat();//屬性和方法都被繼承了</script> </head> <body></body> </html>7.5 構造函數的原型方法繼承:拷貝繼承(for-in)
function Person (name, age) {this.type = 'human'this.name = namethis.age = age }Person.prototype.sayName = function () {console.log('hello ' + this.name) }function Student (name, age) {Person.call(this, name, age) }// 原型對象拷貝繼承原型對象成員 for(var key in Person.prototype) {Student.prototype[key] = Person.prototype[key] }var s1 = Student('張三', 18)s1.sayName() // => hello 張三例子:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>//拷貝繼承;把一個對象中的屬性或者方法直接復制到另一個對象中// var obj1={ // name:"小糊涂", // age:20, // sleep:function () { // console.log("睡覺了"); // } // }; // // //改變了地址的指向 // var obj2=obj1; // console.log(obj2.name,obj2.age); // obj2.sleep();// var obj1={ // name:"小糊涂", // age:20, // sleep:function () { // console.log("睡覺了"); // } // }; // // // var obj2={}; // for(var key in obj1){ // obj2[key]=obj1[key]; // } // console.log(obj2.name);function Person() {}Person.prototype.age=10;Person.prototype.sex="男";Person.prototype.height=100;Person.prototype.play=function () {console.log("玩的好開心");};var obj2={};//Person的構造中有原型prototype,prototype就是一個對象,那么里面,age,sex,height,play都是該對象中的屬性或者方法for(var key in Person.prototype){obj2[key]=Person.prototype[key];}console.dir(obj2);obj2.play();</script> </head> <body></body> </html>7.6 總結繼承
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>//面向對象特性:封裝,繼承,多態//繼承,類與類之間的關系,面向對象的語言的繼承是為了多態服務的,//js不是面向對象的語言,但是可以模擬面向對象.模擬繼承.為了節省內存空間//繼承:/** 原型作用: 數據共享 ,目的是:為了節省內存空間,* 原型作用: 繼承 目的是:為了節省內存空間** 原型繼承:改變原型的指向* 借用構造函數繼承:主要解決屬性的問題* 組合繼承:原型繼承+借用構造函數繼承* 既能解決屬性問題,又能解決方法問題* 拷貝繼承:就是把對象中需要共享的屬性或者犯法,直接遍歷的方式復制到另一個對象中** */</script> </head> <body> </body> </html>7.7 逆推繼承看原型
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>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</script> </head> <body></body> </html>圖解:
8.高階函數
8.1 函數的定義方式
- 函數聲明
- 函數表達式
- new Function
8.2 函數聲明
function foo () {}函數表達式
var foo = function () {}8.3 函數聲明與函數表達式的區別
- 函數聲明必須有名字
- 函數聲明會函數提升,在預解析階段就已創建,聲明前后都可以調用
- 函數表達式類似于變量賦值
- 函數表達式可以沒有名字,例如匿名函數
- 函數表達式沒有變量提升,在執行階段創建,必須在表達式執行之后才可以調用
下面是一個根據條件定義函數的例子:
if (true) {function f () {console.log(1)} } else {function f () {console.log(2)} }以上代碼執行結果在不同瀏覽器中結果不一致。
不過我們可以使用函數表達式解決上面的問題:
var fif (true) {f = function () {console.log(1)} } else {f = function () {console.log(2)} }例子:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>//函數聲明 // // if(true){ // function f1() { // console.log("哈哈,我又變帥了"); // } // }else{ // function f1() { // console.log("小蘇好猥瑣"); // } // } // f1();//函數表達式var ff;if(true){ff=function () {console.log("哈哈,我又變帥了");};}else{ff=function () {console.log("小蘇好猥瑣");};}ff();//函數聲明如果放在if-else的語句中,在IE8的瀏覽器中會出現問題//以后寧愿用函數表達式,都不用函數聲明</script> </head> <body></body> </html>8.4 函數的調用方式
- 普通函數
- 構造函數
- 對象方法
8.5 函數內 this 指向的不同場景
函數的調用方式決定了 this 指向的不同:
| 普通函數調用 | window | 嚴格模式下是 undefined |
| 構造函數調用 | 實例對象 | 原型方法中 this 也是實例對象 |
| 對象方法調用 | 該方法所屬對象 | 緊挨著的對象 |
| 事件綁定方法 | 綁定事件對象 | |
| 定時器函數 | window |
這就是對函數內部 this 指向的基本整理,寫代碼寫多了自然而然就熟悉了。
例子:
<!DOCTYPE html> <html lang="en"> <head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"><title>Document</title> </head> <body></body> </html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>/*** 函數中的this的指向*** 普通函數中的this是誰?-----window* 對象.方法中的this是誰?----當前的實例對象* 定時器方法中的this是誰?----window* 構造函數中的this是誰?-----實例對象* 原型對象方法中的this是誰?---實例對象*** *///嚴格模式: // "use strict";//嚴格模式 // function f1() { // console.log(this);//window // } // f1();//普通函數// function f1() {// console.log(this);// }// f1();//定時器中的this// setInterval(function () {// console.log(this);// },1000);//構造函數// function Person() {// console.log(this);//對象的方法// this.sayHi=function () {// console.log(this);// };// }//原型中的方法// Person.prototype.eat=function () {// console.log(this);// };// var per=new Person();// console.log(per);// per.sayHi();// per.eat();//BOM:中頂級對象是window,瀏覽器中所有的東西都是window的</script> </head> <body></body> </html>8.6 函數也是對象
所有函數都是 Function 的實例
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>//函數是對象,對象不一定是函數//對象中有__proto__原型,是對象//函數中有prototype原型,是對象// function F1() { // } // // console.dir(F1); // // console.dir(Math);//中有__proto__,但是沒有prorotype // // //對象中有__proto__,函數中應該有prototype // // 如果一個東西里面有prototype,又有__proto__,說明是函數,也是對象// // function F1(name) { // this.name=name; // } // // console.dir(F1);//所有的函數實際上都是Function的構造函數創建出來的實例對象 // var f1=new Function("num1","num2","return num1+num2"); // console.log(f1(10,20)); // console.log(f1.__proto__==Function.prototype);//所以,函數實際上也是對象// console.dir(f1);console.dir(Function);</script> </head> <body></body> </html>8.7 數組中函數的調用
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>title</title><script>//數組可以存儲任何類型的數據var arr=[function () {console.log("十一假期快樂");},function () {console.log("十一假期開心");},function () {console.log("十一假期健康");},function () {console.log("十一假期安全");},function () {console.log("十一假期如意");}];//回調函數:函數作為參數使用arr.forEach(function (ele) {ele();});</script> </head> <body></body> </html>總結
本期學習到此結束。
總結
以上是生活随笔為你收集整理的前端学习从入门到高级全程记录之31(JavaScript高级3)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 配置caffe matlab 中遇到的坑
- 下一篇: span标签的用法