国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

溫故知新之javascript面向?qū)ο?

趙連江 / 2707人閱讀

摘要:應(yīng)該非常小心,避免出現(xiàn)不使用命令直接調(diào)用構(gòu)造函數(shù)的情況。上面代碼表示,使用屬性,確定實(shí)例對象的構(gòu)造函數(shù)是,而不是。當(dāng)然,從繼承鏈來看,只有一個(gè)父類,但是由于在的實(shí)例上,同時(shí)執(zhí)行和的構(gòu)造函數(shù),所以它同時(shí)繼承了這兩個(gè)類的方法。

基本概念

類和實(shí)例是大多數(shù)面向?qū)ο缶幊陶Z言的基本概念

類:類是對象的類型模板

實(shí)例:實(shí)例是根據(jù)類創(chuàng)建的對象
但是,JavaScript語言的對象體系,不是基于“類”的,而是基于構(gòu)造函數(shù)(constructor)和原型鏈(prototype)。了與普通函數(shù)區(qū)別,構(gòu)造函數(shù)名字的第一個(gè)字母通常大寫。

構(gòu)造函數(shù)的特點(diǎn)有兩個(gè)。

函數(shù)體內(nèi)部使用了this關(guān)鍵字,代表了所要生成的對象實(shí)例。

生成對象的時(shí)候,必需用new命令

new與構(gòu)造函數(shù)

new命令本身就可以執(zhí)行構(gòu)造函數(shù),所以后面的構(gòu)造函數(shù)可以帶括號(hào),也可以不帶括號(hào)。

下面兩行代碼是等價(jià)的。

var v = new Vehicle();
var v = new Vehicle;

應(yīng)該非常小心,避免出現(xiàn)不使用new命令、直接調(diào)用構(gòu)造函數(shù)的情況。為了保證構(gòu)造函數(shù)必須與new命令一起使用,一個(gè)解決辦法是,在構(gòu)造函數(shù)內(nèi)部使用嚴(yán)格模式,即第一行加上use strict

原理:由于在嚴(yán)格模式中,函數(shù)內(nèi)部的this不能指向全局對象,默認(rèn)等于undefined,導(dǎo)致不加new調(diào)用會(huì)報(bào)錯(cuò)(JavaScript不允許對undefined添加屬性)。

new命令的原理

創(chuàng)建一個(gè)空對象,作為將要返回的對象實(shí)例

將這個(gè)空對象的原型,指向構(gòu)造函數(shù)的prototype屬性

將這個(gè)空對象賦值給函數(shù)內(nèi)部的this關(guān)鍵字

開始執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼

即:

var obj  = {};
obj.__proto__ = Base.prototype;
Base.call(obj);

構(gòu)造函數(shù)的return
如果構(gòu)造函數(shù)內(nèi)部有return語句,而且return后面跟著一個(gè)對象,new命令會(huì)返回return語句指定的對象;否則,就會(huì)不管return語句,返回this對象。

如果對普通函數(shù)(內(nèi)部沒有this關(guān)鍵字的函數(shù))使用new命令,則會(huì)返回一個(gè)空對象
這里遇到了一個(gè)問題,問題描述如下普通函數(shù)用new測試的時(shí)候箭頭函數(shù)報(bào)錯(cuò)了

創(chuàng)建對象

JavaScript對每個(gè)創(chuàng)建的對象都會(huì)設(shè)置一個(gè)原型,指向它的原型對象。
當(dāng)我們用obj.xxx訪問一個(gè)對象的屬性時(shí),JavaScript引擎先在當(dāng)前對象上查找該屬性,如果沒有找到,就到其原型對象上找,如果還沒有找到,就一直上溯到Object.prototype對象,最后,如果還沒有找到,就只能返回undefined
例如,創(chuàng)建一個(gè)Array對象:
var arr = [1, 2, 3];
其原型鏈?zhǔn)牵?br>arr ----> Array.prototype ----> Object.prototype ----> null
Array.prototype定義了indexOf()、shift()等方法,因此你可以在所有的Array對象上直接調(diào)用這些方法。
很容易想到,如果原型鏈很長,那么訪問一個(gè)對象的屬性就會(huì)因?yàn)榛ǜ嗟臅r(shí)間查找而變得更慢,因此要注意不要把原型鏈搞得太長。

new Student()
function Student(name) {
    this.name = name;
    this.hello = function () {
        alert("Hello, " + this.name + "!");
    }
}
var xiaoming= new Student("xiaoming"),
    xiaohong= new Student("xiaohong");

xiaoming ↘
xiaohong -→ Student.prototype ----> Object.prototype ----> null
xiaojun ↗
用new Student()創(chuàng)建的對象還從原型上獲得了一個(gè)constructor屬性,它指向函數(shù)Student本身:

xiaoming.constructor === Student.prototype.constructor; // true
Student.prototype.constructor === Student; // true

Object.getPrototypeOf(xiaoming) === Student.prototype; // true

xiaoming instanceof Student; // true
constructor
constructor屬性的作用,是分辨原型對象到底屬于哪個(gè)構(gòu)造函數(shù)。
function F() {};
var f = new F();

f.constructor === F // true
f.constructor === RegExp // false
上面代碼表示,使用constructor屬性,確定實(shí)例對象f的構(gòu)造函數(shù)是F,而不是RegExp。
構(gòu)造函數(shù)繼承 VS 原型鏈繼承
xiaoming.name
//"xiaoming"
xiaohong.name
//"xiaohong"
xiaoming.hello
/*function() {
        alert("Hello, " + this.name + "!");
    }
*/
xiaohong.hello
/*function() {
        alert("Hello, " + this.name + "!");
    }
*/
xiaoming.hello === xiaohong.hello
//false

xiaoming和xiaohong各自的name不同,這是對的,否則我們無法區(qū)分誰是誰了。

xiaoming和xiaohong各自的hello是一個(gè)函數(shù),但它們是兩個(gè)不同的函數(shù),雖然函數(shù)名稱和代碼都是相同的!

如果我們通過new Student()創(chuàng)建了很多對象,這些對象的hello函數(shù)實(shí)際上只需要共享同一個(gè)函數(shù)就可以了,這樣可以節(jié)省很多內(nèi)存。

要讓創(chuàng)建的對象共享一個(gè)hello函數(shù),根據(jù)對象的屬性查找原則,我們只要把hello函數(shù)移動(dòng)到xiaoming、xiaohong這些對象共同的原型上就可以了,也就是Student.prototype

修改代碼如下:

function Student(name) {
    this.name = name;
}

Student.prototype.hello = function () {
    alert("Hello, " + this.name + "!");
};
xiaoming.hello === xiaohong.hello
//true
繼承方式對比

借用構(gòu)造函數(shù)繼承
基本思想很簡單,在子類型的構(gòu)造函數(shù)內(nèi)部調(diào)用父類型的構(gòu)造函數(shù):

function SuperType(){
 this.colors = ["red", "blue", "green"];
}
function SubType(){
     //繼承了 SuperType
     SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green"

問題:方法都在構(gòu)造函數(shù)內(nèi)部定義,函數(shù)的復(fù)用性就無從談起了。在超類型的原型中定義的方法,對子類型而言是不可見的。考慮這些問題,借用構(gòu)造函數(shù)也是很少多帶帶使用。

組合繼承
實(shí)現(xiàn)的思路是使用原型鏈實(shí)現(xiàn)對原型屬性和方法的繼承,而通過constructor stealing技術(shù)實(shí)現(xiàn)對實(shí)例屬性的繼承。

function SuperType(name){
     this.name = name;
     this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
     alert(this.name);
};
function SubType(name, age){
     //繼承屬性
     SuperType.call(this, name);
     this.age = age;
}

//繼承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
     alert(this.age);
};

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29

var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27

組合繼承避免了原型鏈和借用構(gòu)造函數(shù)的缺陷,融合兩者之長,是最常用的JS繼承模式。

原型式繼承
如果只是想讓一個(gè)對象與另一個(gè)對象保持類似的情況下,沒有必要興師動(dòng)眾地創(chuàng)建構(gòu)造函數(shù)。我們可以使用原型式繼承。
Rect.prototype = Object.create(Shape.prototype);

原型繼承
JavaScript的原型繼承實(shí)現(xiàn)方式就是:

定義新的構(gòu)造函數(shù),并在內(nèi)部用call()調(diào)用希望“繼承”的構(gòu)造函數(shù),并綁定this;

借助中間函數(shù)F實(shí)現(xiàn)原型鏈繼承,最好通過封裝的inherits函數(shù)完成;

繼續(xù)在新的構(gòu)造函數(shù)的原型上定義新方法。

var print = require("./print.js");

function Student(props) {
    this.name = props.name || "Unnamed";
}

Student.prototype.hello = function () {
    print("Hello, " + this.name + "!");
};

function Sub(props) {
    Student.call(this, props);
    this.grade = props.grade || 1;
}

Sub.prototype.getGrade = function() {
    return this.grade;
};

function inherits(Child, Parent) {
    var F = function() {};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
}

inherits(Sub, Student);

var xiaoming = new Sub({
    name: "xiaoming",
    grade: 100
});

print(xiaoming.name + " " + xiaoming.grade);

print(xiaoming instanceof Student);
print(xiaoming instanceof Sub);

class繼承
class Student {
    constructor(name) {
        this.name = name;
    }

    hello() {
        alert("Hello, " + this.name + "!");
    }
}
class PrimaryStudent extends Student {
    constructor(name, grade) {
        super(name); // 記得用super調(diào)用父類的構(gòu)造方法!
        this.grade = grade;
    }

    myGrade() {
        alert("I am at grade " + this.grade);
    }
}

ES6引入的class和原有的JavaScript原型繼承有什么區(qū)別呢?實(shí)際上它們沒有任何區(qū)別,class的作用就是讓JavaScript引擎去實(shí)現(xiàn)原來需要我們自己編寫的原型鏈代碼。簡而言之,用class的好處就是極大地簡化了原型鏈代碼。
這里遇到的問題是isPrototypeOf的問題

多重繼承

JavaScript不提供多重繼承功能,即不允許一個(gè)對象同時(shí)繼承多個(gè)對象。但是,可以通過變通方法,實(shí)現(xiàn)這個(gè)功能。

function M1() {
  this.hello = "hello";
}

function M2() {
  this.world = "world";
}

function S() {
  M1.call(this);
  M2.call(this);
}
S.prototype = M1.prototype;

var s = new S();
s.hello // "hello"
s.world // "world"
s instanceof M2
//false

上面代碼中,子類S同時(shí)繼承了父類M1和M2。當(dāng)然,從繼承鏈來看,S只有一個(gè)父類M1,但是由于在S的實(shí)例上,同時(shí)執(zhí)行M1和M2的構(gòu)造函數(shù),所以它同時(shí)繼承了這兩個(gè)類的方法。

擴(kuò)展

apply的應(yīng)用:轉(zhuǎn)換類似數(shù)組的對象

Array.prototype.slice.apply({0:1,length:1})
// [1]

Array.prototype.slice.apply({0:1})
// []

Array.prototype.slice.apply({0:1,length:2})
// [1, undefined]

Array.prototype.slice.apply({length:1})
// [undefined]

bind結(jié)合call,可以改寫一些JavaScript原生方法的使用形式

[1, 2, 3].slice(0, 1)
// [1]

// 等同于

Array.prototype.slice.call([1, 2, 3], 0, 1)
// [1]

call方法實(shí)質(zhì)上是調(diào)用Function.prototype.call方法,因此上面的表達(dá)式可以用bind方法改寫。

var push = Function.prototype.call.bind(Array.prototype.push);
var pop = Function.prototype.call.bind(Array.prototype.pop);

var a = [1 ,2 ,3];
push(a, 4)
a // [1, 2, 3, 4]

pop(a)
a // [1, 2, 3]

某個(gè)屬性到底是原型鏈上哪個(gè)對象自身的屬性。

function getDefiningObject(obj, propKey) {
  while (obj && !{}.hasOwnProperty.call(obj, propKey)) {
    obj = Object.getPrototypeOf(obj);
  }
  return obj;
}

獲取實(shí)例對象obj的原型對象,有三種方法。

obj.__proto__
obj.constructor.prototype
Object.getPrototypeOf(obj)

推薦最后一種

面向?qū)ο蟾杏X還沒怎么搞明白,模塊的東西還沒弄明白,有時(shí)間補(bǔ)上

參考資料

廖雪峰老師的教程
阮一峰老師的教程
BruceYuj的博客

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/92352.html

相關(guān)文章

  • SegmentFault 技術(shù)周刊 Vol.32 - 七夕將至,你的“對象”還好嗎?

    摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...

    李昌杰 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.32 - 七夕將至,你的“對象”還好嗎?

    摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...

    Lyux 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.32 - 七夕將至,你的“對象”還好嗎?

    摘要:很多情況下,通常一個(gè)人類,即創(chuàng)建了一個(gè)具體的對象。對象就是數(shù)據(jù),對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍(lán)圖或原型。在中,對象通過對類的實(shí)體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實(shí)例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...

    AaronYuan 評(píng)論0 收藏0
  • js溫故知新7(面向對象編程)——學(xué)習(xí)廖雪峰的js教程

    摘要:不區(qū)分類和實(shí)例的概念,而是通過原型來實(shí)現(xiàn)面向?qū)ο缶幊獭P聞?chuàng)建的的原型鏈?zhǔn)且簿褪钦f,的原型指向函數(shù)的原型。最后,創(chuàng)建一個(gè)對象代碼和前面章節(jié)完全一樣小明繼承用定義對象的另一個(gè)巨大的好處是繼承更方便了。 JavaScript不區(qū)分類和實(shí)例的概念,而是通過原型(prototype)來實(shí)現(xiàn)面向?qū)ο缶幊獭?原型是指當(dāng)我們想要?jiǎng)?chuàng)建xiaoming這個(gè)具體的學(xué)生時(shí),我們并沒有一個(gè)Student類型可用...

    Jaden 評(píng)論0 收藏0
  • 2017-09-27 前端日報(bào)

    摘要:前端日報(bào)精選是如何工作的內(nèi)存管理如何處理個(gè)常見的內(nèi)存泄漏譯中的面向?qū)ο笤驮玩溊^承源碼事件機(jī)制考拉升級(jí)經(jīng)驗(yàn)掘金中文第期你知道編譯與解釋的區(qū)別嗎視頻在白鷺引擎中的實(shí)踐王澤變量自定義屬性使用指南眾成翻譯禁止手機(jī)虛擬鍵盤彈出做 2017-09-27 前端日報(bào) 精選 JavaScript是如何工作的:內(nèi)存管理 + 如何處理4個(gè)常見的內(nèi)存泄漏(譯) js中的面向?qū)ο蟆⒃汀⒃玩湣⒗^承Vue....

    wangym 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

趙連江

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<