91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

發布時間:2020-08-01 23:32:40 來源:網絡 閱讀:225 作者:huanghanzhilian 欄目:web開發

轉載請注明出處

原文連接 http://blog.huanghanlian.com/article/5b698f14b8ea642ea9213f50

面向對象編程,oop并不是針對與javascript,很多語言都實現了oop這樣一個編程發法論,比如說java,c++,都是實現了oop的語言。

概念與繼承

概念

面向對象程序設計(Object-oriented programming OOP)是一種程序設計范型,同時也是一種程序開發的方法。對象指的是類的實例,它將對象作為程序的基本單元,將程序和數據封裝其中,以提高軟件的重用性,靈活性和擴展性。 來自于 ----維基百科

OOP重點的一些特性:

  • 繼承

  • 封裝

  • 多態

  • 抽象

基于原型的繼承

function Foo() {
    this.y = 2;
};
Foo.prototype.x = 1;
console.log(Foo.prototype); //object
var obj1 = new Foo();
console.log(obj1.y); //2
console.log(obj1.x); //1

函數聲明創建Foo()函數,這個函數就會有一個內置的Foo.prototype,并且這個屬性是對象,并且是預設的。

function Foo() {
    this.y = 2;
};

console.log(Foo.prototype); //object

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

function Foo() {
    this.y = 2;
};
Foo.prototype.x = 1;
console.log(Foo.prototype); //object

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

然后我們把Foo.prototype對象增加一個屬性x并且賦值為1。

function Foo() {
    this.y = 2;
};
Foo.prototype.x = 1;
console.log(Foo.prototype); //object
var obj1 = new Foo();
console.log(obj1.y); //2
console.log(obj1.x); //1 

然后使用new操作符new Foo();來創建一個Foo();的實例,叫obj1,

當時用new去調用函數的時候,那么構造器也就是說這樣一個函數就會作為一個構造器來使用,并且this會指向一個對象,而對象的原型會指向構造器的Foo.prototype屬性。obj1實際上會成為Foo構造器中的this,最后會作為返回值,并且在構造器里面調用的時候會把y賦值為2,并且obj1的原型,也就是他的proto會指向Foo.prototype內置屬性,最后可以看到obj.y會返回2,obj.x會返回1,y是這個對象上的直接量,而x是原型鏈上的,也就是Foo.prototype的

    function Foo() {
        this.y = 2;
    };
    Foo.prototype.x = 1;
    console.log(Foo.prototype);
    var obj1 = new Foo();

    console.log(obj1);

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

prototype屬性與原型

    function Foo() {};
    console.log(Foo.prototype);
    Foo.prototype.x=1;
    var obj=new Foo();

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

使用函數聲明去中創建一個函數的時候,這個函數就會有一個prototype屬性,并且他默認會有兩個屬性。

  • 一個是constructor:Fooconstructor屬性會指向它本身Foo。

  • 另外一個屬性是__proto____proto__Foo.prototype的原型,那么他的原型會指向Object.prototype也就是說一般的對象比如用花括號括起來的對象字面量,他也會有__proto__他會指向Object.prototype因此Object.prototype上面的一些方法比如說toStringvalueOf才會被每一個一般的對象所使用,

x:1這個是我通過賦值語句增加的。

這句是Foo.prototype的結構

也就是說,這里面有一個Foo函數,這個Foo函數呢會有一個prototype的對象屬性,他的作用呢就是在當使用new Foo()去構造Foo的實例的時候,那么構造器的prototype的屬性,會用作new出來的這些對象的原型。

所以要搞清楚prototype和原型是兩回事。

prototype是函數對象上的預設的對象屬性,而原型呢是我們對象上的一個原型,原型通常都是他的構造器的prototype屬性。

實現class繼承另外一個class

function Person(name, age) {
    this.name = name;
    this.age = age;
};

Person.prototype.hi = function() {
    console.log('Hi my name is' + this.name + ",I'm" + this.age + "years old new");
};

Person.prototype.legs_num = 2;
Person.prototype.arms_num = 2;
Person.prototype.walk = function() {
    console.log(this.name + "is walking...");
};

function Student(name, age, className) {
    Person.call(this, name, age);
    this.className = className;
};
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.hi = function() {
    console.log('Hi my name is' + this.name + ",I'm" + this.age + "years old new,and form" + this.className + ".");
};

Student.prototype.learn = function(subject) {
    console.log(this.name + 'is learing' + subject + 'at' + this.className + '.');
};

console.log(Student.prototype);

var t = new Student("黃繼鵬", 23, "class2");
t.hi();
console.log(t.legs_num);
t.walk();
t.learn('math')

這里有一個函數Person,人的意思意思是說只要人類的class。 在這個構造函數里面,通過this.name = name;this.age = age;去做一個賦值,如何Person作為函數直接去調用的話,那么這里的this會指向全局對象,在瀏覽器里就會指向window,使用new去調用Person函數的時候,this會指向一個原型為Person.prototype的一個空對象,然后通過this.name去給這個空對象賦值,最后這里沒有寫返回值,使用new會this會作為返回值。

通過Person.prototype.hi來創建所有Person實例共享的方法。

再創建Student函數,學生這樣一個class,那么學生是也是人,他是可以繼承人的,每一個學生也是人,并且學生會有他的班級名稱或者一些其他的功能方法,

function Student(name, age, className) {
    Person.call(this, name, age);
    this.className = className;
};

創建Student函數,這里多傳了一個className參數,在Student函數也算是子類里先調用下父類,Person.call(this, name, age);然后把this作為Person里面的this再把name和age傳進去,注意這里的this在new被實例的時候會是這個實例的返回值也就是直接量,

this.className = className;并且把Student的實例做好賦值,

把Student.prototype能繼承Person.prototype的一些方法

Student.prototype = Object.create(Person.prototype);

使用這樣一個方法去拿到Person.prototype對象作為原型的值,這樣Student.prototype原型就會有Person.prototype的值了。

如果去掉Object.create()的話。人有一些方法,但是學生也有自己的一些方法,Student.prototype = Person.prototype;Person.prototype;賦值給Student.prototype的時候,當我想增加學生自己的方法時,比如說

Student.prototype.learn = function(subject) {
    console.log(this.name + 'is learing' + subject + 'at' + this.className + '.');
};

這樣的話由于他們指向的是同一個對象,給Student.prototype增加對象的時候同時也給Person.prototype;增加了同樣的屬性,這不是我們想要的。

所以說通過Student.prototype = Object.create(Person.prototype);創建了一個空的對象,而這個空對象的原型指向了Person.prototype

這樣的話我們既可以在訪問Student.prototype的時候,可以向上查找Person.prototype同時可以在不影響Person.prototype的前提下創建一些自己的Student.prototype上的方法。

Student.prototype.constructor = Student;

每一個prototype屬性對象都會有一個constructor屬性,他的值是指向函數本身,實際上這里面沒有太大的用處,因為我們可以任意的去修改,但是為了保證一致性,我們把這個改成Student.prototype.constructor = Student;

面向對象例子測試

function Person(name, age) {
    this.name = name;
    this.age = age;
};

Person.prototype.hi = function() {
    console.log('Hi my name is' + this.name + ",I'm" + this.age + "years old new");
};

Person.prototype.legs_num = 2;
Person.prototype.arms_num = 2;
Person.prototype.walk = function() {
    console.log(this.name + "is walking...");
};

function Student(name, age, className) {
    Person.call(this, name, age);
    this.className = className;
};
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.hi = function() {
    console.log('Hi my name is' + this.name + ",I'm" + this.age + "years old new,and form" + this.className + ".");
};

Student.prototype.learn = function(subject) {
    console.log(this.name + 'is learing' + subject + 'at' + this.className + '.');
};

var t = new Student("黃繼鵬", 23, "class2");
var poi=new Person("李漢",22);
console.log(poi);
console.log(t);

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

再談原型鏈

再談原型鏈

function Person(name, age) {
    this.name = name;
    this.age = age;
};

Person.prototype.hi = function() {
    console.log('Hi my name is' + this.name + ",I'm" + this.age + "years old new");
};

Person.prototype.legs_num = 2;
Person.prototype.arms_num = 2;
Person.prototype.walk = function() {
    console.log(this.name + "is walking...");
};

function Student(name, age, className) {
    Person.call(this, name, age);
    this.className = className;
};
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.hi = function() {
    console.log('Hi my name is' + this.name + ",I'm" + this.age + "years old new,and form" + this.className + ".");
};

Student.prototype.learn = function(subject) {
    console.log(this.name + 'is learing' + subject + 'at' + this.className + '.');
};

console.log(Student.prototype);

var peng = new Student("黃繼鵬", 23, "class2");
peng.hi();
console.log(peng.legs_num);
peng.walk();
peng.learn('math')

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

這個圖里面說明了上面代碼例子的示意圖

通過var peng = new Student("黃繼鵬", 23, "class2");來創建了一個實例peng

peng的實例他的原型我們用__proto__表示,就會指向構造器Student.prototype的屬性。

Student.prototype上面有hilearn方法,Student.prototype是通過Student.prototype = Object.create(Person.prototype);構造的,所以說Student.prototype是一個對象,并且的原型指向Person.prototype

Person.prototype。也給她設置了很多屬性,hi...等。

Person.prototype.hi = function() {
    console.log('Hi my name is' + this.name + ",I'm" + this.age + "years old new");
};

Person.prototype.hi其實是內置的普通對象,內置對象他本身也會有他的原型,他的原型就是Object.prototype

也就是因為這樣所以說隨便一個對象才會有hasOwnPropertyvalueOftoString等一些公共的函數,這些函數都是從Object.prototype而來的。

當我們去調用

peng.hi();方法的時候,首先看這個對象上本身有沒有hi方法,在本身沒有所以會像上查找,差遭到peng原型也就是Student.prototype有這樣一個函數方法,所以最終調用的是Student.prototype上面的hi方法。

如果Student.prototype不去寫hi方法的時候peng.hi();會去調用Person.prototype.hi這樣一個方法,

當我們調用peng.walk();的時候,先找peng上發現沒有,然后Student.prototype上面,也沒有,Person.prototypewalk所以最終調用結果是Person.prototype上面的walk方法。

那么我想去調用peng.toString的時候也是一層一層向上查找。找到Object.prototype那么最后到null也就是最根源沒有了。

關于一切的一般對象都會指向Object.prototype做一個實際的實驗

var obj={x:1,y:2}

比如用obj等于一個花括號空的字面量,給他屬性。

那么我們知道obj就是一個普通的對象,obj.x就為1

可以通過obj.__proto__這樣的機制可以讓你去訪問對象的原型

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

除了obj.__proto__以外,在es5里面提供了一個方法能夠返回一個對象的原型,就是Object.getPrototypeOf(obj)這樣一個方法,可以返回對象原型,

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

通過三個等號來判斷Object.getPrototypeOf(obj)是不是等于Object.prototype

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

返回true

也就是說我們隨便一個對象仔面了也好或者是函數函數內置的prototype屬性然后去判斷 他的原型可以看到也是Object.prototype

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

也正因為如此所以說我們才可以調用obj.toString()obj.valueOf()
實際上這些方法都是取自Object.prototype上的,

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

并不是所有對象最終原型鏈上最終都有Object.prototype

比如說我們創建obj2對象,然后用var obj2=Object.create(null)obj2.create(null)的作用是創建空對象,并且這個對象的原型指向這樣一個參數,但是這里參數是null,obj2這個時候他的原型就是undefinedobj2.toString就是undefined那么通過Object.create(null)創建出來的對象,就沒有Object.prototype的一些方法。所以說并不是所有的對象都繼承Object.prototype

只是一般我們對象字面量或者是函數的prototype預制的一般的對象上都有Object.prototype

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

并不是所有的函數對象都有prototype這樣一個預制屬性的

function abc() {};
console.log(abc.prototype);
var hh = abc.bind(null);
console.log(hh.prototype);

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

使用es5友誼和bind函數,bind函數是用來修改函數在運行時的this的,bind函數返回的也是一個函數,但是bind函數就沒有prototype預設屬性。

prototype屬性

javascript中的prototype原型,不像java的class,是一旦寫好了以后不太容易去動態改變的,但是javascript中原型實際上也是普通的對象,那么意味著在程序運行的階段我們也可以動態的給prototype添加或者刪除一些屬性,

function Person(name, age) {
    this.name = name;
    this.age = age;
};

Person.prototype.hi = function() {
    console.log('Hi my name is' + this.name + ",I'm" + this.age + "years old new");
};

Person.prototype.legs_num = 2;
Person.prototype.arms_num = 2;
Person.prototype.walk = function() {
    console.log(this.name + "is walking...");
};

function Student(name, age, className) {
    Person.call(this, name, age);
    this.className = className;
};
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.hi = function() {
    console.log('Hi my name is' + this.name + ",I'm" + this.age + "years old new,and form" + this.className + ".");
};

Student.prototype.learn = function(subject) {
    console.log(this.name + 'is learing' + subject + 'at' + this.className + '.');
};

console.log(Student.prototype);

var peng = new Student("黃繼鵬", 23, "class2");
peng.hi();
console.log(peng.legs_num);
peng.walk();
peng.learn('math')

Student.prototype.x=101;
console.log(peng.x);//101

Student.prototype={y:2};
console.log(peng.y);//undefined
console.log(peng.x);//101

var nunnly=new Student("nunnly", 23, "class3");

console.log(nunnly.y);//2
console.log(nunnly.x);//undefined

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

Student.prototype.x=101;
console.log(peng.x);//101

Student.prototype={y:2};
console.log(peng.y);//undefined
console.log(peng.x);//101

var nunnly=new Student("nunnly", 23, "class3");

console.log(nunnly.y);//2
console.log(nunnly.x);//undefined

比如說這里的Student.prototype同過Student.prototype.x=101;huang的原型動態的添加一個屬性x那么我們發現所有的實例都會受到影響,現在去調用console.log(peng.x);發現他賦值為101了,

直接修改Student.prototype={y:2};構造器的屬性,把他賦值為一個新的對象,y:2

有趣的現象

console.log(peng.y);//undefined
console.log(peng.x);//101

當我們去修改Student.prototype的時候并不能修改已經實例化的對象,也就是說已經實例化的peng他的原型已經指向當時的Student.prototype如果你修改了Student.prototype的話,并不會影響已經創建的實例,之所以修改的x沒有問題,是因為我們修改的是peng原型的那個對象,

但是再去用new重新實例化對象,那么會發現x不見了,并且y是新的y值。

內置構造器的prototype

Object.prototype.x = 1;
var obj = {
    y: 3
};
console.log(obj.x); //1
for (var key in obj) {
    console.log(key + "=" + obj[key]); //y=3 x=1
}

比如說我們想讓所有的對象他的原型鏈上都會有x屬性會發現所有對象都會有x屬性,這樣的設置會在for...in的時候會被枚舉出來,那么怎么解決這個問題呢

Object.defineProperty(Object.prototype, 'x', {writable: true,value: 1});
var obj = {
    y: 3
};
console.log(obj.x); //1
for (var key in obj) {
    console.log(key + "=" + obj[key]); //y=3
}
  • value:屬性的值給屬性賦值
  • writable:如果為false,屬性的值就不能被重寫。
  • get: 一旦目標屬性被訪問就會調回此方法,并將此方法的運算結果返回用戶。
  • set:一旦目標屬性被賦值,就會調回此方法。
  • configurable:如果為false,則任何嘗試刪除目標屬性或修改屬性以下特性(writable, configurable, enumerable)的行為將被無效化。
  • enumerable:是否能在for...in循環中遍歷出來或在Object.keys中列舉出來。

創建對象-new/原型鏈

function foo(){}    //定義函數對象 foo
foo.prototype.z = 3;      //函數對象默認帶foo.prototype對象屬性  這個對象會作為new實例的對象原型  對象添加z屬性=3

var obj =new foo();    //用構造器方式構造新的對象
obj.y = 2;    //通過賦值添加2個屬性給obj
obj.x = 1;   //通過new去構造這樣一個對象他的主要特點是,他的原型會指向構造器的foo.prototype屬性

//一般foo.prototype對象他的原型又會指向Object.prototype
//Object.prototype他也會有他的原型最后指向null整個原型鏈的末端

obj.x; // 1  //訪問obj.x發現對象上有x返回1
obj.y; // 2  //訪問obj.y發現對象上有x返回2
obj.z; // 3  //obj上沒有z并不會停止查找,會去查找他的原型foo.prototype.z返回3
typeof obj.toString; // ‘function'  這是一個函數,toString是Object.prototype上面的每個對象都有
'z' in obj; // true     obj.z是從foo.prototype繼承而來的,所以說obj里面有z
obj.hasOwnProperty('z'); // false   表示z并不是obj直接對象上的,而是對象原型鏈上的。

JavaScript 精粹 基礎 進階(8)OOP面向對象編程(上)

instanceof

instanceof

instanceof數據類型判斷方法

console.log([1, 2] instanceof Array); //true
console.log(new Object() instanceof Array); //false

左邊要求是一個對象instanceof右邊要求是一個函數或者說構造器
他會判斷右邊的構造器的 prototype的屬性是否出現在左邊這個對象的原型鏈上。

console.log([1, 2] instanceof Array); //true

[1,2]這里是數組字面量,數組的字面量他也有他的原型,他的原型就是Array.prototype所以返回true

console.log(new Object() instanceof Array); //false

new Object()new一個空對象空對象的原型會指向Object.prototypenew Object()的原型鏈不是Array.prototype所以返回false

需要注意的是

console.log([1, 2] instanceof Object); //true

因為數組他的原型是Array.prototype,而Array.prototype的原型就是Object.prototype,所以返回true

所以說instanceof我們可以判斷某一個對象他的原型鏈上是否有右邊這個函數構造器的prototype對象屬性。

function per() {};

function sor() {};
sor.prototype = new per();
sor.prototype.constructor = sor;

var peng = new sor();
var han = new per();
console.log(peng instanceof sor); //true
console.log(peng instanceof per); //true
console.log(han instanceof sor); //false
console.log(han instanceof per); //true

實現繼承的方式

實現繼承的方式

if (!Object.create) {
    Object.create = function(proto) {
        function F() {};
        F.prototype = proto;
        return new F();
    };
}

function Person(name, age) {
    this.name = name;
    this.age = age;
};

Person.prototype.hi = function() {
    console.log('Hi my name is' + this.name + ",I'm" + this.age + "years old new");
};

Person.prototype.legs_num = 2;
Person.prototype.arms_num = 2;
Person.prototype.walk = function() {
    console.log(this.name + "is walking...");
};

function Student(name, age, className) {
    Person.call(this, name, age);
    this.className = className;
};
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.hi = function() {
    console.log('Hi my name is' + this.name + ",I'm" + this.age + "years old new,and form" + this.className + ".");
};

Student.prototype.learn = function(subject) {
    console.log(this.name + 'is learing' + subject + 'at' + this.className + '.');
};

console.log(Student.prototype);

var t = new Student("黃繼鵬", 23, "class2");
t.hi();
console.log(t.legs_num);
t.walk();
t.learn('math');

Object.create()也有他的問題,他是es5之后才支持的,但是沒有關系在es5之前我們可以寫一個模擬的方法。

if (!Object.create) {
    Object.create = function(proto) {
        function F() {};
        F.prototype = proto;
        return new F();
    };
}

這里面我們可以判斷下有沒有Object.create如果沒有的話,我們可以把他賦值為一個函數,這里會傳進來一個參數,寫一個臨時的空函數,把空函數的prototype屬性賦值給想要作為原型的對象,然后返回new F(),會創建一個對象,這個對象的原型指向構造器的prototype,利用這樣的規則返回空對象,并且對象原型指向參數也就是要繼承的原型。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

静安区| 固阳县| 临海市| 宁明县| 霍城县| 巫溪县| 揭东县| 宁城县| 九寨沟县| 渝中区| 永平县| 株洲市| 邓州市| 辽阳县| 临夏县| 韶山市| 云林县| 杭锦旗| 云梦县| 兴业县| 边坝县| 宜兰县| 栾城县| 兴山县| 南靖县| 广饶县| 涪陵区| 南雄市| 宁阳县| 梁山县| 长兴县| 永定县| 鄯善县| 丹棱县| 高青县| 西贡区| 德州市| 同江市| 迭部县| 浦江县| 略阳县|