成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

javascript的面向?qū)ο?,原型鏈及繼承

Xufc / 3388人閱讀

摘要:也就是說,不必在構(gòu)造函數(shù)中添加定義對(duì)象信息,而是可以直接將這些信息添加到原型中。子類的屬性,表示構(gòu)造函數(shù)的繼承,總是指向父類。以前,這些原生構(gòu)造函數(shù)是無法繼承的。

面向?qū)ο?/b>

js是一門基于對(duì)象的語言。js中的一切皆對(duì)象;

console.log(Object.prototype.toString.call(123)) //[object Number]        
console.log(Object.prototype.toString.call("123")) //[object String]      
console.log(Object.prototype.toString.call(undefined)) //[object Undefined] 
console.log(Object.prototype.toString.call(true)) //[object Boolean]      
console.log(Object.prototype.toString.call({})) //[object Object]        
console.log(Object.prototype.toString.call([])) //[object Array]      
console.log(Object.prototype.toString.call(function(){})) //[object Function]


new function

    var a = function () {};
    console.log(typeof a);//function
    
    var b = new function () {};
    console.log(typeof b);//object
    
    var c = new Function ();
    console.log(typeof c);//function
    
new function 是一個(gè)JavaScript中用戶自定義的對(duì)象

    var obj = function (name) {
        this.name = name;
    };
    var b = new obj("aaa")=o == Object.create(obj.prototype);;
    console.log(b.name);  
    // 創(chuàng)建一個(gè)以另一個(gè)空對(duì)象為原型,且擁有一個(gè)屬性p的對(duì)象
    o = Object.create({}, { p: { value: 42 } })
    
    // 省略了的屬性特性默認(rèn)為false,所以屬性p是不可寫,不可枚舉,不可配置的:
    o.p = 24
    o.p
    //42

私有變量和函數(shù)
在函數(shù)內(nèi)部定義的變量和函數(shù),叫局部(內(nèi)部)變量和函數(shù),如果不對(duì)外提供接口,外部是無法訪問到的。

function Box(){
    var color = "blue"; //私有變量
    var fn = function(){} //私有函數(shù)
}
var obj = new Box();
    alert(obj.color); //彈出 undefined,訪問不到私有變量
    alert(obj.fn); //同上

靜態(tài)變量和函數(shù)
定義一個(gè)函數(shù)后加"."來添加的屬性和函數(shù),該函數(shù)可以訪問到,但實(shí)例訪問不到。

function Obj(){};

Obj.num = 72; //靜態(tài)變量
Obj.fn = function() { } //靜態(tài)函數(shù)
  
alert(Obj.num); //72
alert(typeof Obj.fn) //function

var t = new Obj();
alert(t.name); //undefined
alert(typeof t.fn); //undefined

實(shí)例變量和函數(shù)

function Box(){
    this.a=[]; //實(shí)例變量
    this.fn=function(){} //實(shí)例方法
}

var box1=new Box();
box1.a.push(1);
box1.fn={};
console.log(box1.a); //[1]
console.log(typeof box1.fn); //object

var box2=new Box();
console.log(box2.a); //[]
console.log(typeof box2.fn); //function

box1中修改了afn,而在box2中沒有改變,由于數(shù)組和函數(shù)都是對(duì)象,是引用類型,這就說明box1中的屬性和方法與box2中的屬性與方法雖然同名但卻不是一個(gè)引用,而是對(duì)Box對(duì)象定義的屬性和方法的一個(gè)復(fù)制。

ES5 構(gòu)造函數(shù)

構(gòu)造函數(shù)(constructor),其實(shí)就是一個(gè)普通函數(shù),但是內(nèi)部使用了this變量,對(duì)構(gòu)造函數(shù)使用new運(yùn)算符,就能生成實(shí)例,并且this變量會(huì)綁定在實(shí)例對(duì)象上。

function Cat(name,color){
    this.name=name;
    this.color=color;
}
Cat.prototype.type=function(){};

var cat1=new Cat()

這時(shí)cat1會(huì)自動(dòng)含有一個(gè)constructor屬性,指向它們的構(gòu)造函數(shù)。

alert(cat1.constructor==Cat);//true

alert(cat instanceof Cat);//true

js提供了一個(gè)instanceof運(yùn)算符,用來檢驗(yàn)cat1是否是Cat的實(shí)例對(duì)象。

原型對(duì)象與實(shí)例對(duì)象之間的關(guān)系。

構(gòu)造函數(shù)(constructor):每new生成一個(gè)實(shí)例,就相當(dāng)于在內(nèi)存上又復(fù)制了一次
原型對(duì)象(prototype):而portotype,所有的實(shí)例都只指向一個(gè)內(nèi)存地址,用于不變的屬性和方法

不管是構(gòu)造函數(shù)內(nèi)部還是原型對(duì)象,里面的this在沒有new之前都指向該構(gòu)造函數(shù)Cat

Cat.prototype.constructor===Cat //true
alert(Cat.prototype.isPrototypeof(cat1)) //true

isPrototypeOf()用來判斷某個(gè)prototype對(duì)象和某個(gè)實(shí)例之間的關(guān)系

alert(cat1.hasOwnProperty("name")); // true
alert(cat1.hasOwnProperty("type")); // false 

hasOwnProperty()用來判斷某個(gè)屬性到底是本地屬性,還是繼承自prototype對(duì)象的屬性。本地為true

in運(yùn)算符用來判斷,某個(gè)實(shí)例是否含有某個(gè)屬性,不管是不是本地屬性。還可以用來遍歷某個(gè)對(duì)象的所有屬性。

alert("name" in cat1);//true
for(var i in cat1){alert("cat1["+i+"]="+cat1[i])}
繼承

構(gòu)造函數(shù)綁定

    function Cat(name,color){

    Animal.apply(this, arguments);//等于是把父類的實(shí)例屬性復(fù)制了一份給子類實(shí)例裝上了,占內(nèi)存

    this.name = name;
    this.color = color;

  }

  var cat1 = new Cat("大毛","黃色");
  alert(cat1.species); // 動(dòng)物

利用prototype

    Cat.prototype = new Animal(); //由于prototype 引用類型指向同一個(gè)地址會(huì)影響其它實(shí)例,而且不能向父傳參
  Cat.prototype.constructor = Cat; //把prototype指向原來的構(gòu)造函數(shù)

組合繼承

    function Cat(){
        Animal.call(this);
    }
    Cat.prototype = new Animal(); //比較常用,占內(nèi)存
 

通過空對(duì)象

    function extend(Child, Parent) {
    
    var F = function(){}; //利用一個(gè)空對(duì)象去轉(zhuǎn)接prototype,而且空對(duì)象幾乎不占內(nèi)存,不會(huì)影響父對(duì)象
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    
    Child.prototype.constructor = Child; //糾正回來它的構(gòu)造函數(shù)指向
    Child.uber = Parent.prototype; //輔助屬性,可以直接調(diào)用父的方法
  }

    function Animal(){ }
  Animal.prototype.species = "動(dòng)物";

    function Cat(name,color){
        this.name=name
        this.color=color
    }

    extend(Cat,Animal);

  var cat1 = new Cat("大毛","黃色");
  alert(cat1.species); // 動(dòng)物

拷貝繼承

    function extend2(Child, Parent) {
    
    var p = Parent.prototype;
    var c = Child.prototype;
    
    for (var i in p) { //循環(huán)父的原型方法給到子
      c[i] = p[i];
    }

    c.uber = p;

  } 

    extend2(Cat, Animal);

  var cat1 = new Cat("大毛","黃色");
  alert(cat1.species); // 動(dòng)物
原型和原型鏈

私有變量和函數(shù)
在函數(shù)內(nèi)部定義的變量和函數(shù),叫局部(內(nèi)部)變量和函數(shù),如果不對(duì)外提供接口,外部是無法訪問到的。

function Box(){
    var color = "blue"; //私有變量
    var fn = function(){} //私有函數(shù)
}
var obj = new Box();
    alert(obj.color); //彈出 undefined,訪問不到私有變量
    alert(obj.fn); //同上

靜態(tài)變量和函數(shù)
定義一個(gè)函數(shù)后加"."來添加的屬性和函數(shù),該函數(shù)可以訪問到,但實(shí)例訪問不到。

function Obj(){};

Obj.num = 72; //靜態(tài)變量
Obj.fn = function() { } //靜態(tài)函數(shù)
  
alert(Obj.num); //72
alert(typeof Obj.fn) //function

var t = new Obj();
alert(t.name); //undefined
alert(typeof t.fn); //undefined

實(shí)例變量和函數(shù)

function Box(){
    this.a=[]; //實(shí)例變量
    this.fn=function(){} //實(shí)例方法
}

var box1=new Box();
box1.a.push(1);
box1.fn={};
console.log(box1.a); //[1]
console.log(typeof box1.fn); //object

var box2=new Box();
console.log(box2.a); //[]
console.log(typeof box2.fn); //function

box1中修改了afn,而在box2中沒有改變,由于數(shù)組和函數(shù)都是對(duì)象,是引用類型,這就說明box1中的屬性和方法與box2中的屬性與方法雖然同名但卻不是一個(gè)引用,而是對(duì)Box對(duì)象定義的屬性和方法的一個(gè)復(fù)制。

我們創(chuàng)建的每個(gè)函數(shù)都有一個(gè)prototype屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)對(duì)象,這個(gè)對(duì)象的用途是包含可以由特定類型的所有實(shí)例共享的屬性和方法。那么,prototype就是通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例的原型對(duì)象。

使用原型的好處是可以讓對(duì)象實(shí)例共享它所包含的屬性和方法。也就是說,不必在構(gòu)造函數(shù)中添加定義對(duì)象信息,而是可以直接將這些信息添加到原型中。使用構(gòu)造函數(shù)的主要問題就是每個(gè)方法都要在每個(gè)實(shí)例中創(chuàng)建一遍。

JavaScript中,一共有兩種類型的值,原始值和對(duì)象值。每個(gè)對(duì)象都有一個(gè)內(nèi)部屬性 prototype ,我們通常稱之為原型。原型的值可以是一個(gè)對(duì)象,也可以是null。如果它的值是一個(gè)對(duì)象,則這個(gè)對(duì)象也一定有自己的原型。這樣就形成了一條線性的鏈,我們稱之為原型鏈。

函數(shù)可以用來作為構(gòu)造函數(shù)來使用。另外只有函數(shù)才有prototype屬性并且可以訪問到,但是對(duì)象實(shí)例不具有該屬性,只有一個(gè)內(nèi)部的不可訪問的__proto__屬性。__proto__是對(duì)象中一個(gè)指向相關(guān)原型的神秘鏈接。按照標(biāo)準(zhǔn),__proto__是不對(duì)外公開的

當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)實(shí)例的時(shí)候,實(shí)例內(nèi)部將包含一個(gè)內(nèi)部指針(__proto__)指向構(gòu)造函數(shù)的prototype,這個(gè)連接存在于實(shí)例和構(gòu)造函數(shù)的prototype之間,而不是實(shí)例與構(gòu)造函數(shù)之間。

function Person(name){                             //構(gòu)造函數(shù)
    this.name=name;
}

Person.prototype.printName=function() {//原型對(duì)象
    alert(this.name);
}

var person1=new Person("Byron"); //實(shí)例化對(duì)象
console.log(person1.__proto__); //Person
console.log(person1.constructor); //Person
console.log(Person.prototype); //指向原型對(duì)象Person
var person2=new Person("Frank");

Person的實(shí)例person1中包含了name屬性,同時(shí)自動(dòng)生成一個(gè)__proto__屬性,該屬性指向Personprototype,可以訪問到prototype內(nèi)定義的printName方法

實(shí)例就是通過構(gòu)造函數(shù)創(chuàng)建的。實(shí)例一創(chuàng)造出來就具有constructor屬性(指向構(gòu)造函數(shù))和__proto__屬性(指向原型對(duì)象),

構(gòu)造函數(shù)中有一個(gè)prototype屬性,這個(gè)屬性是一個(gè)指針,指向它的原型對(duì)象。
原型對(duì)象內(nèi)部也有一個(gè)指針(constructor屬性)指向構(gòu)造函數(shù):Person.prototype.constructor = Person;

實(shí)例可以訪問原型對(duì)象上定義的屬性和方法。
在這里person1person2就是實(shí)例,prototype是他們的原型對(duì)象。

原型鏈的示意圖可以用下圖來表示:

ES6


-

基本上,ES6class可以看作只是一個(gè)語法糖,它的絕大部分功能,ES5都可以做到,新的class寫法只是讓對(duì)象原型的寫法更加清晰、更像面向?qū)ο缶幊痰恼Z法而已。

class Point { //類名
    constructor(x, y) { //構(gòu)造函數(shù),constructor方法默認(rèn)返回實(shí)例對(duì)象(即this)
        this.x = x; //this關(guān)鍵字代表實(shí)例對(duì)象
        this.y = y;
    }
    toString() { //prototype原型對(duì)象
        return "(" + this.x + ", " + this.y + ")";
    }
}

typeof Point // "function"
Point === Point.prototype.constructor // true

    

上面代碼表明,類的數(shù)據(jù)類型就是函數(shù),類本身就指向構(gòu)造函數(shù)。

let point = new Point(1,2); //也是直接使用new命令,傳給constructor的值
point.toString(); //(1,2)
point.hasOwnProperty("x") //true,自身的屬性(因?yàn)槎x在this變量上),
point.hasOwnProperty("toString") //false/此屬性是定義在原型上
point.__proto__.hasOwnProperty("toString") //true

point.constructor === Point.prototype.constructor //true

在類的實(shí)例上面調(diào)用方法,其實(shí)就是調(diào)用原型上的方法。

由于類的方法都定義在prototype對(duì)象上面,所以類的新方法可以添加在prototype對(duì)象上面。Object.assign方法可以很方便地一次向類添加多個(gè)方法。

class Point {
    constructor(){ //可以忽略不寫,會(huì)自動(dòng)添加
        // ...
    }
}
Object.assign(Point.prototype, {
    toString(){},
    toValue(){}
});

prototype對(duì)象的constructor屬性,直接指向“類”的本身,這與ES5的行為是一致的。

Point.prototype.constructor === Point //true,類內(nèi)部的方法不能枚舉,和es5不一樣
繼承

Class之間可以通過extends關(guān)鍵字實(shí)現(xiàn)繼承,這比ES5的通過修改原型鏈實(shí)現(xiàn)繼承,要清晰和方便很多。

class ColorPoint extends Point {}//相當(dāng)于var ColorPoint=new Point也就是ColorPoint繼承了Point

上面代碼定義了一個(gè)ColorPoint類,該類通過extends關(guān)鍵字,繼承了Point類的所有屬性和方法。但是由于沒有部署任何代碼,所以這兩個(gè)類完全一樣,等于復(fù)制了一個(gè)Point類。es6的繼承是先新建父類的實(shí)例,再在子類中繼承修改this的指向

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); //調(diào)用父類的constructor(x, y)給父類傳值,用來新建父類的this對(duì)象。
    this.color = color;
  }
  toString() {
    return this.color + " " + super.toString(); // ES6 規(guī)定,通過super調(diào)用父類的方法時(shí),super會(huì)綁定子類的this。
  }
}

let cp = new ColorPoint(25, 8, "green");
cp instanceof ColorPoint // true
cp instanceof Point // true

ES5的繼承,實(shí)質(zhì)是先創(chuàng)造子類的實(shí)例對(duì)象this,然后再將父類的方法添加到this上面Parent.apply(this)。
ES6的繼承機(jī)制完全不同,實(shí)質(zhì)是先創(chuàng)造父類的實(shí)例對(duì)象this(所以必須先調(diào)用super方法),然后再用子類的構(gòu)造函數(shù)修改this。

繼承鏈
大多數(shù)瀏覽器的ES5實(shí)現(xiàn)之中,每一個(gè)對(duì)象都有__proto__屬性,指向?qū)?yīng)的構(gòu)造函數(shù)的prototype屬性。ES6同時(shí)有prototype屬性和__proto__屬性,因此同時(shí)存在兩條繼承鏈。

(1)子類的__proto__屬性,表示構(gòu)造函數(shù)的繼承,總是指向父類。
(2)子類prototype屬性的__proto__屬性,表示方法的繼承,總是指向父類的prototype屬性。

class A {}

class B extends A {}

B.__proto__ === A  //true,es5中,是constructor,實(shí)例
B.prototype.__proto__ === A.prototype  //true,es5中,是B._proto_===A.prototype,方法

這樣的結(jié)果是因?yàn)?,類的繼承是按照下面的模式實(shí)現(xiàn)的。

// B的實(shí)例繼承A的實(shí)例
Object.setPrototypeOf(B.prototype, A.prototype) = B.prototype.__proto__ = A.prototype;
const b = new B();

// B的實(shí)例繼承A的靜態(tài)屬性
Object.setPrototypeOf(B, A) = B.__proto__ = A;
const b = new B();

《對(duì)象的擴(kuò)展》一章給出過Object.setPrototypeOf方法的實(shí)現(xiàn)。

Object.setPrototypeOf = function (obj, proto) {
  obj.__proto__ = proto;
  return obj;
}

這兩條繼承鏈,可以這樣理解:作為一個(gè)對(duì)象,子類(B)的原型(__proto__屬性)是父類(A);作為一個(gè)構(gòu)造函數(shù),子類(B)的原型(prototype屬性)是父類的實(shí)例。

Object.create(A.prototype);
// 等同于
B.prototype.__proto__ = A.prototype;
    實(shí)例的__proto__屬性

子類實(shí)例的__proto__屬性的__proto__屬性,指向父類實(shí)例的__proto__屬性。也就是說,子類的原型的原型,是父類的原型。

var p1 = new Point(2, 3);
var p2 = new ColorPoint(2, 3, "red");

p2.__proto__ === p1.__proto__ // false
p2.__proto__.__proto__ === p1.__proto__ // true

三種特殊情況。

第一種特殊情況,子類繼承Object類。

class A extends Object {}

A.__proto__ === Object //true
A.prototype.__proto__ === Object.prototype //true

這種情況下,A其實(shí)就是構(gòu)造函數(shù)Object的復(fù)制,A的實(shí)例就是Object的實(shí)例。

第二種特殊情況,不存在任何繼承。

class A {}
//因?yàn)锳就是一個(gè)函數(shù),所以它繼承的自然就是函數(shù)。就相當(dāng)于new Function,但它的prototype是一個(gè)對(duì)象,所以繼承自對(duì)象

A.__proto__ === Function.prototype // true
A.prototype.__proto__ === Object.prototype // true

這種情況下,A作為一個(gè)基類(即不存在任何繼承),就是一個(gè)普通函數(shù),所以直接繼承Funciton.prototype。但是,A調(diào)用后返回一個(gè)空對(duì)象(即Object實(shí)例),所以A.prototype.__proto__指向構(gòu)造函數(shù)(Object)的prototype屬性。

第三種特殊情況,子類繼承null。

class A extends null {}

A.__proto__ === Function.prototype // true,表明new出來的都是函數(shù),A是函數(shù)
A.prototype.__proto__ === undefined // true,因?yàn)槔^承自null,所以它的_proto_找不著,就是undefined

這種情況與第二種情況非常像。A也是一個(gè)普通函數(shù),所以直接繼承Funciton.prototype。但是,A調(diào)用后返回的對(duì)象不繼承任何方法,所以它的__proto__指向Function.prototype,即實(shí)質(zhì)上執(zhí)行了下面的代碼。

class C extends null {
  constructor() { return Object.create(null); 
}

原生構(gòu)造函數(shù)的繼承

原生構(gòu)造函數(shù)是指語言內(nèi)置的構(gòu)造函數(shù),通常用來生成數(shù)據(jù)結(jié)構(gòu)。ECMAScript的原生構(gòu)造函數(shù)大致有下面這些。

Boolean()
Number()
String()
Array()
Date()
Function()
RegExp()
Error()
Object()

以前,這些原生構(gòu)造函數(shù)是無法繼承的。

class MyDate extends Date{

    getTest(){
        console.log("我是MyDate的擴(kuò)展方法",this===date,new Date(),new MyDate(),)
        // this向的是它的實(shí)例對(duì)象,this===date
    }
}

let date=new MyDate();
console.log(date.getTime());//本地時(shí)間
date.getTest() //我是MyDate的擴(kuò)展方法 true

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92754.html

相關(guān)文章

  • javascript原型鏈及繼承理解

    原型鏈及繼承的理解 定義函數(shù) function A(name) { // 構(gòu)造內(nèi)容(構(gòu)造函數(shù)) this.name = name; /* // 也支持定義方法。但為了性能,不建議在構(gòu)造里定義方法 this.fn = function(parmas){ // your code } */ } // 原型鏈 A.pro...

    ziwenxie 評(píng)論0 收藏0
  • 淺談 JavaScript 原型

    摘要:數(shù)組的構(gòu)造函數(shù)是原型鏈的指向與其他除以外的構(gòu)造函數(shù)相同,的也指向頂級(jí)原型對(duì)象,每一個(gè)數(shù)組都是的實(shí)例,都指向。實(shí)例對(duì)象查找構(gòu)造函數(shù)原型對(duì)象的方法一般會(huì)把對(duì)象共有的屬性和方法都放在構(gòu)造函數(shù)的原型對(duì)象上。 showImg(https://segmentfault.com/img/remote/1460000018998704?w=900&h=506); 閱讀原文 概述 在 JavaScr...

    explorer_ddf 評(píng)論0 收藏0
  • 面向對(duì)象 JavaScript

    摘要:是完全的面向?qū)ο笳Z言,它們通過類的形式組織函數(shù)和變量,使之不能脫離對(duì)象存在。而在基于原型的面向?qū)ο蠓绞街校瑢?duì)象則是依靠構(gòu)造器利用原型構(gòu)造出來的。 JavaScript 函數(shù)式腳本語言特性以及其看似隨意的編寫風(fēng)格,導(dǎo)致長期以來人們對(duì)這一門語言的誤解,即認(rèn)為 JavaScript 不是一門面向?qū)ο蟮恼Z言,或者只是部分具備一些面向?qū)ο蟮奶卣鳌1疚膶⒒貧w面向?qū)ο蟊疽?,從?duì)語言感悟的角度闡述為什...

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

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

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

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

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

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

0條評(píng)論

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