[華為云在線課程][JavaScript的面向對象][學習筆記]
第1章,JavaScript的面向對象機制
1.1,JavaScript的面向對象的對象
JavaScript對象的概念:
現實生活中:萬物皆對象,對象是一個具體的事物,看得見摸得著的實物
例如,一本書,一輛汽車,一個人可以是"對象",一個數據庫,一張網頁一個與遠程服務器的連接也可以是"對象"
在JavaScript中,對象是一組無序的相關屬性和方法的集合,所有的事物都是對象,例如字符串、數值、數組、函數等
對象是由屬性和方法組成的:
屬性:事物的特征,在對象中用屬性來表示
方法:事物的行為,在對象中用方法來表示
JavaScript創建對象的方式:
利用構造函數創建對象
利用字面量創建對象
利用new Object創建對象
使用對象的優點:
JavaScript中的對象表達結構更清晰,更強大
對象是復雜數據類型object
對象就是一組無序的相關屬性和方法的集合
/* * 創建對象三種方式之一:使用對象字面量創建對象 * {} -> 包含表這個具體事物的屬性和方法,以鍵值對形式存在 * 鍵:相當于屬性名稱 * 值:相當于屬性值,可以是任意值 * */ var star = { "name": "hello", "age": "30", "gender": "男", "height": "200", "sayHi": function () { alert("hello world"); } } /* * 訪問對象的屬性 * 對象.屬性名 * 對象['屬性名'] --> 屬性名在中括號中必須加引號 * 對象.方法名() --> 方法名后面必須加上() * */ console.log(star.name);//hello console.log(star['age']);//30 console.log(star.sayHi());//hello world
/* * 創建對象三種方式之二:利用 new Object 創建對象 * */ var hello = new Object(); hello.name = "hello's name"; hello.age = "10"; hello.sayHi = function () { console.log("function saiHi()"); }
/* * 創建對象三種方式之三:利用構造函數創建對象 * 提取對象中的一些公共的屬性和方法,封裝到這個函數里 * 構造函數名首字母要大寫 * */ function 構造函數名(形參1, 形參2, 形參3) { this.屬性名1 = 參數1; this.屬性名2 = 參數2; this.屬性名3 = 參數3; } var obj = new 構造函數名(實參1, 實參2, 實參3);
1.2,JavaScript的構造函數
JavaScript構造函數
一種特殊的函數,主要用來初始化對象,即為對象成員變量賦初始值,它總與new運算符一起使用,我們可以把對象中一些公共的屬性和方法抽取出來,然后封裝到這個函數里面
利用構造函數創建對象
構造函數的語法格式:
function 構造函數名() { this.屬性 = 值; this.方法 = function () { } } new 構造函數名();
JavaScript構造函數和對象案例:
構造函數:如Person(),抽象了對象的公共部分,封裝到了函數里面,它泛指某一大類(class)
構造對象:如new Person(),特指某一個對象,通過new關鍵字創建對象的過程我們也稱為對象實例化
只有以new關鍵字來調用的時候,我們才能說這是一個構造函數
構造函數的執行過程:
當以new關鍵字調用時,會創建一個新的內存空間
函數體內部的this執行該內存
執行函數體內部的代碼
默認返回我們的this
function Person(name, age, gender) { this.name = name; this.age = age; this.gender = gender; this.info = function () { console.log("姓名是:" + this.name + ",年齡是:" + this.age + ",性別是:" + this.gender); }; } var person = new Person("hello", 10, "男"); console.log(person.name);//hello person.info();//姓名是:hello,年齡是:10,性別是:男
1.3,JavaScript的new命令
new命令在執行時會做四件事情:
在內存中創建一個新的空對象
讓this指向這個新的對象
執行構造函數里面的代碼,給這個新對象添加屬性和方法
返回這個新對象(所以構造函數里面不需要return)
JavaScript的new命令案例:
//構造函數 function Stu(name, age, address) { this.name = name; this.age = age; this.address = address; this.showInfo = function () { console.log("姓名:" + this.name + ",年齡:" + this.age + ",地址:" + this.address); }; } //利用new來調用我的構造函數 var stu = new Stu("張三", 10, "地球");//創建一個新的內存 stu.showInfo();//姓名:張三,年齡:10,地址:地球
JavaScript利用字面量創建對象:
對象字面量:就是花括號{}里面包含了表達這個具體事物(對象)的屬性和方法
對象的調用:
對象里面的屬性調用:對象.屬性名,這個小點.就理解為"的"
對象里面屬性的另一種調用方式:對象[‘屬性名’],注意方括號里面的屬性必須加引號
對象里面的方法調用:對象.方法名(),注意這個方法名后面一定加括號
//創建一個Object對象,簡寫 var p1 = {}; //動態增加屬性、方法 p1.name = "hello"; p1.age = 10; p1.sayHi = function () { alert("function: " + p1.name); }; p1.sayHi();
JavaScript利用new Object創建對象
//利用new Object創建對象 //創建了一個空的對象 var obj = new Object(); obj.name = "hello"; obj.age = 1; obj.gender = "男"; obj.sayHi = function () { console.log("world, " + obj.name); }; console.log(obj.name);//hello console.log(obj["age"]);//1 obj.sayHi();//world, hello
JavaScript面向對象之封裝
封裝就是把抽象出來的屬性和對屬性的操作封裝在一起,屬性被保護在內部,程序的其他部分只有通過被授權的操作函數,才能對屬性進行操作
function Person(_name, _age, _salary) { //Person類的公開屬性,類的公開屬性的定義方式是:"this.屬性名" this.name = _name; //Person類的私有屬性,類的私有屬性的定義方式是:"var 屬性名" var age = _age; var salary = _salary; //定義Person類的公開方法(特權方法),類的公開方法的定義方式是:"this.functionName=function(){...}" this.Show = function () { //在公開方法里面訪問類的私有屬性是允許的 console.log("Age=" + age + "\t" + "Salary=" + salary); }; /* * 定義Person類的私有方法(內部方法) * 類的私有方法的定義方式是:”function functionName(){...}“ * 或者var functionName = function(){...} * */ function privateFn() { console.log("我是Person類的私有函數privateFn"); } var privateFn2 = function () { console.log("我是Person類的私有函數privateFn2"); }; } var p1 = new Person("hello", 1, 100); //訪問公有屬性,這是可以正常訪問的 console.log("p1.Name=" + p1.name);//p1.Name=hello //不能使用類的對象去直接訪問類私有屬性,這是訪問不了的,結果都是undefined console.log("p1.Age=" + p1.age + "\t" + "p1.Salary=" + p1.salary);//p1.Age=undefined p1.Salary=undefined //調用類的公共函數,這是允許的 p1.Show();//Age=1 Salary=100 //不能使用類的對象去調用類的私有方法,這里會報錯對象不支持此屬性或者方法"" console.log("p1.privateFn():" + p1.privateFn() + "p1.privateFn2():" + p1.privateFn2());//Uncaught TypeError: p1.privateFn is not a function
1.4,JavaScript的原型對象
JavaScript中ES5中沒有類Class,但是它取了一個新的名字叫"原型對象",因此"類=原型對象"
類(原型對象)是抽象,是概念的,代表一類事物;對象是具體的,實際的,代表一個具體的事物
每個對象一定會有一個原型對象
原型對象實際是構造實例對象的構造器中的一個屬性,只不過這個屬性是個對象
這個原型對象中的屬性與方法,都會被對象實例所共享(類似Java中的類方法,類屬性)
原型對象的屬性不是對象實例的屬性,只要修改原型對象上的屬性和方法,變動就會立刻體現在所有對象實例上
JavaScript對每個創建的對象都會設置一個屬性__proto__,指向它的原型對象xxx.prototype
JavaScript中,每個函數都有一個prototype屬性,這個屬性指向函數的原型對象:
函數的prototype指向了一個對象,而這個對象正是調用構造函數時創建的實例的原型,也就是person1和person2的原型
原型的概念:每一個JavaScript對象(除null外)創建的時候,就會與之關聯另一個對象,這個對象就是我們所說的原型,每一個對象都會從原型中"繼承"屬性。
function Person(age) { this.age = age; } Person.prototype.dname = "hello"; var person1 = new Person(); var person2 = new Person(); console.log(person1.dname);//hello console.log(person2.dname);//hello
JavaScript中,每個對象(除null外)都會有的屬性,叫做__proto__,這個屬性會指向該對象的原型:
function Person() { } var person1 = new Person(); var person2 = new Person(); console.log(person1.__proto__ === Person.prototype);//true console.log(person1.__proto__ === person2.__proto__);//true
JavaScript中,每個原型都有一個constructor屬性,指向該關聯的構造函數
function Person() { } console.log(Person === Person.prototype.constructor);//true
/* * in操作符 * 只要對象或者原型有一地方存在這個屬性,就會返回true * */ function Person() { } Person.prototype.name = "hello"; var p1 = new Person(); p1.sex = "男"; alert("sex" in p1);//對象本身添加的 所以會返回true alert("name" in p1);//原型中存在,所以會返回true alert("age" in p1);//對象原型中都不存在,所以會返回false
function Person() { } Person.prototype.name = "hello"; var p1 = new Person(); p1.sex = "男"; //定義一個函數去判斷原型所在的位置 function propertyLocation(obj, prop) { if (!(prop in obj)) { alert(prop + "屬性不存在"); } else if (obj.hasOwnProperty(prop)) { alert(prop + "該屬性存在此對象中"); } else { alert(prop + "該屬性存在此對象的原型中"); } } propertyLocation(p1, "age");//age屬性不存在 propertyLocation(p1, "name");//name該屬性存在此對象的原型中 propertyLocation(p1, "sex");//sex該屬性存在此對象中
第2章,JavaScript的面對對象繼承
繼承
繼承是面向對象語言的一個重要概念
許多面向對象語言都支持兩種繼承方式:接口繼承和實現繼承;接口繼承只繼承方法簽名,而實現繼承則繼承實際的方法
由于函數沒有簽名,所以ECMAScript只支持實現繼承,而實現繼承主要是依靠原型鏈來實現的
2.1,JavaScript原型繼承
原型繼承
基本思想:利用原型讓一個引用類型繼承另一個引用類型的屬性和方法
核心:將父類的實例作為子類的原型
缺點:父類新增原型方法/原型屬性,子類都能夠訪問到,并且父類一變其他都變了
function Animal() { this.species = "動物"; this.colors = ["白色"]; } function Cat(name, eat) { this.name = name; this.cat = eat; } Cat.prototype = new Animal(); var cat1 = new Cat("貓", "老鼠"); console.log(cat1.species);//動物 console.log(cat1.colors);//['白色']
/* * 原型繼承存在的問題: * Cat的所有的實例都會共享colors屬性 * */ function Animal() { this.species = "動物"; this.colors = ["白色"]; } function Cat(name, eat) { this.name = name; this.eat = eat; } Cat.prototype = new Animal(); var cat1 = new Cat("貓", "老鼠"); console.log(cat1.species);//動物 console.log(cat1.colors);//['白色'] cat1.colors.push("黑色"); console.log(cat1.colors);//['白色', '黑色'] var cat2 = new Cat("大貓", "魚"); console.log(cat2.colors);//['白色', '黑色']
構造函數繼承:
基本思想:在子類型構造函數的內部調用超類型構造函數。函數只不過是在特定環境中執行代碼的對象,因此可通過使用call()和apply()在新創建的對象上執行構造函數
因為屬性是綁定在this上面的,所以調用的時候才賦值到了相應的實例中,各個實例的值就不會相互影響了
核心:使用父類的構造函數來增強子類的實例,等于是賦值父類的實例屬性給子類(沒有用到原型)
缺點:方法都在構造函數中定義,只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法,無法實現函數的復用,每一個子類都有父類實例函數的副本,影響性能
function Animal() { this.species = "動物"; this.colors = ["白色"]; } function Cat(name, eat) { Animal.apply(this, arguments); this.name = name; this.eat = eat; } var cat1 = new Cat("貓", "魚"); //動物 console.log(cat1.species);//動物 cat1.colors.push("黑色"); console.log(cat1.colors);//['白色', '黑色'] var cat2 = new Cat("狗", "-"); console.log(cat2.colors);//['白色']
/* * 構造繼承存在問題: * 1,方法都在構造函數中定義,所以沒法利用函數的復用 * 2,并且在超類型的原型中定義的方法對于子類型而言是不可見的 * */ function Animal() { this.species = "動物"; this.colors = ["白色"]; } Animal.prototype.getColor = function () { return this.colors; }; function Cat(name, eat) { Animal.apply(this, arguments); this.name = name; this.eat = eat; } var cat1 = new Cat("貓", "魚"); console.log(cat1.species);//動物 cat1.colors.push("黑色"); console.log(cat1.colors);//['白色', '黑色'] console.log(cat1.getColor()); var cat2 = new Cat("狗", "-");
2.2,JavaScript的組合繼承
基本思想:使用原型鏈實現對原型屬性和方法的繼承,而通過構造函數實現對實例屬性的繼承
組合繼承是最常用的繼承方法
核心:通過調用父類構造,繼承父類的屬性并保留傳參的優點,然后再通過將父類實例作為子類原型,實現函數復用
缺點:調用了兩次父類構造函數,生成了兩份實例(子類實例將子類原型上的那一份給屏蔽)
function Animal(species) { this.species = species; this.colors = ["白色"]; } Animal.prototype.getColor = function () { console.log(this.colors); }; function Cat(name, eat) { this.name = name; this.eat = eat; Animal.call(this, name); } //繼承方法 Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; Cat.prototype.sayName = function () { console.log(this.name); }; var cat1 = new Cat("貓", "吃魚"); cat1.colors.push("黑色"); console.log(cat1.colors);//['白色', '黑色'] cat1.getColor();//['白色', '黑色'] cat1.sayName();//貓 var cat2 = new Cat("波斯貓", "吃貓糧"); console.log(cat2.colors);//['白色'] cat2.getColor();//['白色'] cat2.sayName();//波斯貓
JavaScript的面向對象的多態:
同一操作作用于不同的對象上面,可以產生不同的解釋和不同的執行結果
var makeSound = function (person) { if (person && person.sound instanceof Function) { person.sound(); } }; var Student = function () { }; Student.prototype.sound = function () { console.log("學生通過發出聲音練習英語"); }; var Employee = function () { }; Employee.prototype.sound = function () { console.log("員工通過發出聲音溝通工作"); }; makeSound(new Student());//學生通過發出聲音練習英語 makeSound(new Employee());//員工通過發出聲音溝通工作
2.3,JavaScript的This關鍵字
普通函數中的this
單獨使用this,指的是全局對象,在瀏覽器中,window就是全局對象,在嚴格模式下,單獨使用this指向的還是全局
在函數中使用this,函數的所屬者就會被綁定在this上,在瀏覽器中,window就是全局對象,嚴格模式就沒有綁定在全局上,this就是undefined
//在es5中 function foo() { //這里的this是window console.log(this); } foo();//Window {window: Window, self: Window, document: document, name: '', location: Location,…}
//在es5中 function foo() { 'use strict'; //這里的this是undefined console.log(this); } foo();//undefined
對象方法中this
在對象中使用this,指向的就是我們的對象
var obj = { info: "tom", showInfo: function () { //這里的this是obj console.log(this.info); } }; obj.showInfo();//tom
構造函數中this
在構造函數中使用,指向具體的某個實例
function Foo(name, age) { //這里的this指的是具體的某個實例f1或f2 this.name = name; this.age = age; this.showName = function () { //這里的this指的是具體的某個實例f1或f2 console.log(this.name); }; } var f1 = new Foo("hello", 1); f1.showName();//hello var f2 = new Foo("world", 2); f2.showName();//world
面向對象中的this
指向的是一個構造函數創建的實例,原型里面就是指通過原型所屬構造函數創建出來的實例
function Foo(info) { //這里的this指的是該構造函數創建出來的實例,這個this和原型中的this是同一個指向 this.info = info; } Foo.prototype.showInfo = function () { //原型里面的this指的是通過原型所屬的構造函數創建出來的實例 console.log(this.info); }; var f1 = new Foo("hello"); f1.showInfo();//hello
JavaScript
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。