一、Javascript數據類型
1、基本數據類型:Number String Boolean Null Undefined
基本數據類型是按值訪問的,因為可以直接操作保存在變量中的實際值
var a = 10;
var b = a;
b = 20;
console.log(a); // 10值 b的改變對a沒有影響
上面,b獲取的是a值得一份拷貝,雖然,兩個變量的值相等,但是兩個變量保存了兩個不同的基本數據類型值。
b只是保存了a復制的一個副本。所以,b的改變,對a沒有影響。
2、引用類型數據:也就是對象類型Object type,比如:Object 、Array 、Function 等。
不可以直接訪問堆內存空間中的位置和操作堆內存空間,只能操作對象在棧內存中的引用地址
所以,引用類型數據在棧內存中保存的實際上是對象在堆內存中的引用地址。通過這個引用地址可以快速查找到保存在堆內存中的對象。
var obj1 = new Object();
var obj2 = obj1;
obj2.name = "我有名字了";
console.log(obj1.name); // 我有名字了 obj2的改變影響了obj1,因為obj1,obj2指向同一塊內存地址
說明這兩個引用數據類型指向了同一個堆內存對象。obj1賦值給onj2,實際上這個堆內存對象在棧內存的引用地址復制了一份給了obj2,
但是實際上他們共同指向了同一個堆內存對象。實際上改變的是堆內存對象。
二、JavaScript 中,萬物皆對象!但對象也是有區別的。分為普通對象和函數對象。
凡是通過 new Function() 創建的對象都是函數對象,其他的都是普通對象。
Object 、Function 是 JavaScript 自帶的函數對象。Object也是函數!
var o1 = {};
var o2 =new Object();
var o3 = new f1();
function f1(){};
var f2 = function(){};
var f3 = new Function('str','console.log(str)');
console.log(typeof Object); //function
console.log(typeof Function); //function
console.log(typeof f1); //function
console.log(typeof f2); //function
console.log(typeof f3); //function
console.log(typeof o1); //object
console.log(typeof o2); //object
console.log(typeof o3); //object
三、構造函數
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() { alert(this.name) }
}
var person1 = new Person('Zaxlct', 28, 'Software Engineer');
var person2 = new Person('Mick', 23, 'Doctor');
person1 和 person2 都是 Person 的實例
這兩個實例都有一個 constructor (構造函數)屬性,該屬性(是一個指針)指向 Person。即:
console.log(person1.constructor == Person); //true
console.log(person2.constructor == Person); //true
我們要記住兩個概念(構造函數,實例):
person1 和 person2 都是 構造函數 Person 的實例
一個公式:
實例的構造函數屬性(constructor)指向構造函數。
person1.constructor == Person
四、原型對象 Person.prototype,主要是為了實現繼承和共享屬性;
function Person(){}
函數是指構造函數,對象or實例是new之后的
每個函數對象都有一個prototype 屬性,即Person.prototype,這個屬性指向函數的原型對象(一個普通對象)。
【公式一】:每個對象都有 proto 屬性,但只有函數對象才有 prototype 屬性
原型對象,顧名思義,它就是一個普通對象(廢話 = =!)。從現在開始你要牢牢記?。?br/>原型對象就是 Person.prototype
它有一個默認的屬性:constructor(構造函數屬性),這個屬性(是一個指針)指向 prototype 屬性所在的函數(Person)
即:Person.prototype.constructor == Person
【結論】:原型對象(Person.prototype)是 構造函數(Person)的一個實例。
五、proto
JS 在創建對象(普通對象、函數對象)的時候,該對象都有proto 的內置屬性,用于指向創建它的構造函數的原型對象。
對象 person1 有一個 proto屬性,創建它的構造函數是 Person,構造函數的原型對象是 Person.prototype
即:person1.proto == Person.prototype
person1.proto == person1的構造函數.prototype
【總結】
Person.prototype.constructor == Person;
person1.__proto__ == Person.prototype;
Person.prototype.__proto__== Object.prototype;
//Person.prototype 是一個普通對象,我們無需關注它有哪些屬性,只要記住它是一個普通對象。一個普通對象的構造函數 === Object
person1.constructor == Person;
不過,要明確的真正重要的一點就是,這個連接存在于實例(person1)與構造函數(Person)的原型對象(Person.prototype)之間,而不是存在于實例(person1)與構造函數(Person)之間。
六、
//注意這個
function f1(){};
var f2 = function(){};
var f3 = new Function('str','console.log(str)');
console.log(typeof Object); //function
console.log(typeof Function); //function
console.log(typeof f1); //function
console.log(typeof f2); //function
console.log(typeof f3); //function
兩個注意事項:
1、我們看proto屬性:
右邊
function Foo(){...};
let f1 = new Foo();
typeof f1; //"object"
typeof Foo; //"function"
Function.__proto__ == Function.prototype; //true
Function.__proto__ == Object.prototype; //false
Foo.__proto__ == Function.prototype; //true,Foo的構造函數是Function
Object.__proto__ == Function.prototype; //true,Object的構造函數是Function
左邊:
f1.constructor == Foo; //true,f1的構造函數是Function
f1.__proto__ == Foo.prototype; //true,f1的構造函數是Function
Foo.prototype.__proto__ == Object.prototype; //true Foo.prototype原型對象,整體看成一個普通對象,構造函數是Object
Object.prototype.__proto__ == null;
【總結】第一,這里我們僅留下proto屬性,它是對象所獨有的,可以看到proto屬性都是由一個對象指向一個對象,即指向它們的原型對象(也可以理解為父對象),那么這個屬性的作用是什么呢?它的作用就是當訪問一個對象的屬性時,如果該對象內部不存在這個屬性,那么就會去它的proto屬性所指向的那個對象(可以理解為父對象)里找,如果父對象也不存在這個屬性,則繼續往父對象的proto屬性所指向的那個對象(可以理解為爺爺對象)里找,如果還沒找到,則繼續往上找….直到原型鏈頂端null(可以理解為原始人。。。),此時若還沒找到,則返回undefined(可以理解為,再往上就已經不是“人”的范疇了,找不到了,到此為止),由以上這種通過proto屬性來連接對象直到null的一條鏈即為我們所謂的原型鏈。
原型鏈和proto有關系,和prototype沒關系
2、prototype屬性:
每個函數對象都有一個prototype 屬性,即Person.prototype,這個屬性指向函數的原型對象(一個普通對象)。
原型對象,顧名思義,它就是一個普通對象(廢話 = =!)。從現在開始你要牢牢記?。?br/>原型對象就是 Person.prototype
它是函數所獨有的,它是從一個函數指向一個對象。它的含義是函數的原型對象,也就是這個函數(其實所有函數都可以作為構造函數)所創建的實例的原型對象,
由此可知:f1.proto === Foo.prototype,它們兩個完全一樣。那prototype屬性的作用又是什么呢?它的作用就是包含可以由特定類型的所有實例共享的屬性和方法,也就是讓該函數所實例化的對象們都可以找到公用的屬性和方法。
3、看一下constructor屬性:
constructor屬性也是對象才擁有的,它是從一個對象指向一個函數,含義就是指向該對象的構造函數,每個對象都有構造函數,從圖中可以看出Function這個對象比較特殊,它的構造函數就是它自己(因為Function可以看成是一個函數,也可以是一個對象),所有函數最終都是由Function()構造函數得來,所以constructor屬性的終點就是Function()。
七、總結一下
我們需要牢記兩點:①proto和constructor屬性是對象所獨有的;② prototype屬性是函數所獨有的,因為函數也是一種對象,所以函數也擁有proto和constructor屬性。
proto屬性的作用就是當訪問一個對象的屬性時,如果該對象內部不存在這個屬性,那么就會去它的proto屬性所指向的那個對象(父對象)里找,一直找,直到proto屬性的終點null,然后返回undefined,通過proto屬性將對象連接起來的這條鏈路即我們所謂的原型鏈。
prototype屬性的作用就是讓該函數所實例化的對象們都可以找到公用的屬性和方法,即f1.proto === Foo.prototype。
八、prototype和proto的關系是什么?
首先,要明確幾個點:
1.在JS里,萬物皆對象。方法(Function)是對象,方法的原型(Function.prototype)是對象。因此,它們都會具有對象共有的特點。
即:對象具有屬性proto,可稱為隱式原型,一個對象的隱式原型指向構造該對象的構造函數的原型,這也保證了實例能夠訪問在構造函數原型中定義的屬性和方法。
2.方法(Function)
方法這個特殊的對象,除了和其他對象一樣有上述_proto_屬性之外,還有自己特有的屬性——原型屬性(prototype),這個屬性是一個指針,指向一個對象,這個對象的用途就是包含所有實例共享的屬性和方法(我們把這個對象叫做原型對象)。原型對象也有一個屬性,叫做constructor,這個屬性包含了一個指針,指回原構造函數。
function Foo(){...};
let f1 = new Foo();
let f2 = new Foo();
Foo():是構造函數,
Foo.prototype:是原型對象,保存著實例共享的方法,所有構造函數聲明的實例(這里是f1,f2)都可以共享這個方法。
同時,該原型對象有一個指針constructor指回構造函數。
即:Foo.prototype.constructor == Foo
比如:Foo.prototype.num = 10; 這個屬性num是綁定在Foo.prototype下面的,實例f1下面沒有這個屬性,但是實例
f1.proto == Foo.prototype,所以,f1通過proto就可以到達Foo.prototype上,尋找Foo.prototype下面是否有這個屬性,
假如Foo.prototype下面也沒有這個屬性,那么通過Foo.prototype.proto == Object.prototype; 假如在Object.prototype上面還沒有找到,那么由于Object.prototype.proto ==null; 也就是說Object.prototype.proto上面沒有大佬了,那么就返回undefined
對于實例f1和f2而言:
f1.proto == Foo.prototype;
f2.proto == Foo.prototype;
f1和f2是Foo這個對象的兩個實例,這兩個對象也有屬性proto,指向構造函數的原型對象,這樣子就可以像上面1所說的訪問原型對象的所有方法了。
另外:
構造函數Foo()除了是方法,也是對象啊,它也有proto屬性,指向誰呢?
指向它的構造函數的原型對象唄。函數的構造函數不就是Function嘛,因此這里的Foo.proto指向了Function.prototype。
其實除了Foo(),Function(), Object()也是一樣的道理。
原型對象也是對象啊,它的proto屬性,又指向誰呢?
同理,指向它的構造函數的原型對象唄。這里是Object.prototype.
最后,Object.prototype的proto屬性指向null。
總結:
1.對象有屬性proto,指向該對象的構造函數的原型對象。
2.方法除了有屬性proto,還有屬性prototype,prototype指向該方法的原型對象
九、
1、hasOwnProperty : 看是不是對象自身下面的屬性,屬于Object身上的方法
var arr = [];
arr.num = 10;
Array.prototype.num2 = 20;
//alert( arr.hasOwnProperty('num') ); //true
alert( arr.hasOwnProperty('num2') ); //false
2、constructor : 查看對象實例的構造函數
function Aaa(){}
var a1 = new Aaa();
alert( a1.constructor ); //Aaa
可以用來判斷某一個實例是否是某一個對象類型
var arr = [];
//下面是兩種判斷方法
console.log( arr.constructor == Array ); //true
console.log( arr instanceOf Array ); //true
原理:
function Aaa(){}
系統自動加上:Aaa.prototype.constructor = Aaa; //每一個函數定義的時候就自動生成,都會有
這樣Aaa.prototype原型對象上就具有constructor這個屬性了
對于let a1 = new Aaa();的a1實例來說,根據原型鏈的關系,a1身上沒有constructor屬性,利用proto向上查找,a1.proto = Aaa.prototype,
a1就具有了constructor屬性,且值為Aaa
即 a1.constructor == Aaa //true
a1.proto.constructor == Aaa //true
3、 instanceof:是運算符,不是面向對象的屬性和方法,和for、if、加減乘除等一樣都是運算符
判斷:對象與構造函數在原型鏈上是否有關系,是否在同一條原型鏈上
function Aaa(){
}
var a1 = new Aaa();
//alert( a1 instanceof Object ); //true
var arr = [];
alert( arr instanceof Array ); //true
4、toString
位置:系統對象本身就有這個屬性,即系統對象下面是自帶的,比如Array下面就有這個屬性,不用到Object上面找了
Array.prototype.toString
對于自己寫的對象來說,本身下面是沒有這個屬性的,是通過原型鏈到Object.prototype下面找到的,注意區別
function Aaa(){}
let a1 = new Aaa();
a1下面也有這個屬性,是通過原型鏈找到的
用法1:把對象轉為字符串
var arr = [1,2,3];
alert( arr.toString() ); //'1,2,3'
用法2:數字轉十六進制
//var num = 255;
//alert( num.toString(16) ); //'ff'
用法3:利用toString做類型的判斷 :
var arr = [];
alert( Object.prototype.toString.call(arr) == '[object Array]' ); // true
5、類型判斷,比如判斷arr是不是數組類型,可以使用constructor、instanceof、toString判斷,使用typeof是判斷不出來的
let arr = [];
arr.constructor == Array // true
arr instanceof Array //true
Object.prototype.toString.call(arr) == '[object Array]' //true
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。