目錄
1.主題:
2.拖拽的構造函數實作
2.1- 拖拽的面相過程寫法
2.2- 拖拽的面相對象寫法
3.構造函數繼承
3.1構造函數繼承:
4.原型的繼承
5.原型的深拷貝繼承
5.1JSON序列化繼承原型
5.2自定義深拷貝函數:
5.3使用自定義深拷貝函數實作原型繼承:
5.3組合繼承
6.原型鍊
7.拖拽的邊界需求 :通過繼承來解決
8.ES6中的類
8.1類的寫法
8.2靜态方法和屬性:執行個體不會繼承的屬性和方法,但是子類還是會繼承父類的靜态方法和屬性
8.3類的繼承:extends
8.4子類重寫父類方法
8.5使用class繼承實作拖拽
9.包裝對象
10.常用方法
10.1hasOwnProperty():看是不是對象自身底下的屬性
10.2contructor()檢視對象的構造函數 可以用來做判斷是屬于哪個構造函數:
10.3instanceof():對象與構造函數是否在原型鍊上有關系。檢測的是原型:
10.4typeof() 傳回的是表達式的資料類型:
10.5toString()判斷類型;
1.主題:
- 拖拽案例
- 構造函數繼承
- 原型的繼承
- 拖拽案例的繼承改造
- es6中的類的用法
2.拖拽的構造函數實作
2.1- 拖拽的面相過程寫法
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#div1 {
width: 100px;
height: 100px;
background: red;
position: absolute;
top: 20px;
left: 50px;
}
#div2 {
width: 100px;
height: 100px;
background: blue;
position: absolute;
top: 200px;
left: 400px;
}
</style>
</head>
<body>
<div id="div1"></div>
<div id="div2"></div>
<script>
{
//需求:面向過程方法實作拖拽
let div1 = document.querySelector("#div1");
div1.addEventListener("mousedown",function(ev){
//浏覽器相容
let e = ev || window.event;
//擷取初始化滑鼠坐标
let startPos = {};
startPos.x = e.clientX;
startPos.y = e.clientY;
//擷取初始left和top
let left = div1.offsetLeft;
let top = div1.offsetTop;
// console.log(startPos);
function move(ev){
let e = ev || window.event;
let curPos = {};
curPos.x = e.clientX;
curPos.y = e.clientY;
// console.log(curPos);
console.log(curPos.x - startPos.x + div1.offsetLeft);
console.log(curPos.y - startPos.y + div1.offsetTop);
div1.style.left = curPos.x - startPos.x + left + 'px';
div1.style.top = curPos.y - startPos.y + top + 'px';
}
document.addEventListener("mousemove",move);
document.addEventListener("mouseup",function(){
document.removeEventListener("mousemove",move);
},{
once:true
});
});
}
</script>
</body>
</html>
2.2- 拖拽的面相對象寫法
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#div1 {
width: 100px;
height: 100px;
background: red;
position: absolute;
top: 20px;
left: 50px;
}
#div2 {
width: 100px;
height: 100px;
background: blue;
position: absolute;
top: 200px;
left: 400px;
}
</style>
</head>
<body>
<div id="div1"></div>
<div id="div2"></div>
<script>
{
//需求:面向對象方法實作拖拽
//構造函數一般隻寫屬性
function Drag(ele){
this.ele = ele;
this.mouseDown();
}
Drag.prototype.mouseDown = function(){
//需要将this傳遞到事件裡:指派或者箭頭函數
this.ele.addEventListener("mousedown",ev=>{
//浏覽器相容
let e = ev || window.event;
//擷取初始化滑鼠坐标,直接求出初始化時滑鼠坐标和left/top的值,以免要傳遞多個參數
let x = e.clientX - this.ele.offsetLeft;
let y = e.clientY - this.ele.offsetTop;
this.mouseMove(x,y);
this.mouseUp(x,y);
});
}
//由于move方法也需要共用,是以也寫在原型上
Drag.prototype.setStyle = function(l,t){
this.ele.style.left = l + 'px';
this.ele.style.top = t + 'px';
}
Drag.prototype.mouseMove = function(x,y){
//如果将onmousemove加在document上并使用監聽和匿名函數,則在move方法中的this會指向document,是以需要加在this.ele
//使用監聽時不好傳遞參數
document.onmousemove = ev=>{
let e = ev || window.event;
let left = e.clientX - x;
let top = e.clientY - y;
this.setStyle(left,top);
};
}
Drag.prototype.mouseUp = function(x,y){
document.onmouseup = ev=>{
//清除滑鼠移動事件可以直接使this.ele.onmousemove = "";
document.onmousemove = "";
};
}
let div1 = document.querySelector("#div1");
let div2 = document.querySelector("#div2");
let drag1 = new Drag(div1);
let drag2 = new Drag(div2);
}
</script>
</body>
</html>
3.構造函數繼承
- 繼承:子類繼承父類所有屬性和行為,父類不受影響。
- 目的:找到類之間的共性精簡代碼
- ES5中,使用call()/apply()/bind()修改this指向來實作繼承
- 隻會繼承父類的構造函數,而不會繼承父類的原型
- 解決原型不會繼承繼承問題:直接将父類原型指派給子類,JOSN序列化拷貝對象,自定義深拷貝方法,組合繼承
- 簡單原型繼承(直接将父類原型指派給子類),當子類修改原型時會影響父類的情況(傳址給子類);
- JOSN序列化原型繼承:當對象中存在undefined和函數時,拷貝的對象會忽略
3.1構造函數繼承:
通過call()/apply()/bind()修改this指向來實作,子類繼承父類所有屬性和行為
//繼承:子類繼承父類的所有屬性和行為,父類不受影響
function Parent(name){
this.eyes = 2;
this.name = name;
this.legs = 2;
}
//寫子類,通過call()/apply()/bind()方法修改子類的this指向,并傳入參數即可
function Son(name){
Parent.call(this,name);
//并由自己的獨特屬性
this.hobby = "打籃球";
}
//發現子類繼承父類後,擁有所有父類的屬性和行為,父類不受影響
let parent = new Parent("老張");
let son = new Son("小明");
console.log(parent);//Parent {eyes: 2, name: "老張", legs: 2}
console.log(son);//Son {eyes: 2, name: "小明", legs: 2, hobby: "打籃球"}
- 繼承問題:繼承隻會繼承父類的構造函數,而不會繼承父類的原型
//繼承:隻會繼承父類的構造函數,而不會繼承父類的原型
Parent.prototype.job = function(){
console.log("程式員");
}
let parent = new Parent("老張");
let son = new Son("小明");
parent.job();//程式員
son.job();//報錯:Uncaught TypeError: son.job is not a function
4.原型的繼承
解決構造函數繼承不能繼承原型問題:直接将父類原型指派給子類;JSON序列化;自定義深拷貝繼承;組合繼承
- - 簡單原型繼承(直接将父類原型指派給子類),出現影響父類的情況;
如下:直接将父類原型指派給子類後,子類擁有了父類的原型,但是當子類修改了原型時,父類原型也收到了影響。是以這種方式不可用。解決:進行深拷貝,見下一節。
//簡單繼承:直接将父類原型指派給子類。問題:修改子類原型時會影響父類
Son.prototype = Parent.prototype;
let parent = new Parent("老張");
let son = new Son("小明");
parent.job();//程式員
son.job();//程式員
//當通過子類Son修改指派得到的原型時,發現父類的原型也發生了改變
Son.prototype.job = function(){
console.log("銷售");
}
parent.job();//銷售
son.job();//銷售
5.原型的深拷貝繼承
深拷貝繼承(JSON序列化/自定義深拷貝函數);組合繼承
Object.assign()方法隻會拷貝一層;arr.flat()方法扁平化多元數組,都不适合多層的深拷貝。
- 傳值和傳址問題:
- - 基本資料類型傳值:Number、String、Boolean、Null、Undefined
- - 複雜資料類型/引用資料類型傳址:Array、Date、Math、RegExp、Object、Function等
5.1JSON序列化繼承原型
- JSON序列化的不足:
- 如果拷貝對象包含函數,或者undefined等值,此方法就會出現問題,不會進行拷貝函數和undefined。
是以如果原型上有為undefined或者函數時,盡量不要使用JSON進行原型拷貝。
//JSON序列化解決不能繼承原型的問題。問題:當對象中有undefined或函數時,不會進行拷貝
let parentProto = {
name:"張三",
age:20,
test:undefined,
fn:function(){
console.log("fn...");
}
};
let sonProto = JSON.parse(JSON.stringify(parentProto));
console.log(parentProto);//{name: "張三", age: 20, test: undefined, fn: ƒ}
console.log(sonProto);//{name: "張三", age: 20}
5.2自定義深拷貝函數:
如果對象上有多層對象嵌套,可以進行深拷貝。
問題1:for...in循環會循環原型上的屬性或方法,是以需要使用hasOwnProperty()方法判斷,傳入的對象自身的屬性而不是原型上的屬性,再進行深拷貝
問題2:但是如果有屬性值為null,通過自定義深拷貝函數進行拷貝後,得到的對象中,null會轉為一個空對象。
//自定義深拷貝函數
let parentProto = {
name:"張三",
age:20,
gender:undefined,
addr:null,
fn:function(){
console.log("fn...");
}
};
function deepCopy(obj){
//判斷參數是對象還是數組,如果是數組就建立新數組進行拷貝,如果是對象就建立新對象進行拷貝
let newObj = Array.isArray(obj)?[]:{};
//通過for...in循環進行拷貝
for(let key in obj){
//hasOwnProperty():看是不是對象自身底下的屬性
//for...in循環會循環原型上的屬性或方法,是以需要使用hasOwnProperty()方法判斷,傳入的對象自身的屬性而不是原型上的屬性,再進行深拷貝
if(obj.hasOwnProperty(key)){
//如果得到的屬性仍然是一個對象,就繼續進行循環
if(typeof obj[key] == "object"){
newObj[key] = deepCopy(obj[key]);
}else{
newObj[key] = obj[key];
}
}
}
return newObj;
}
let sonProto = deepCopy(parentProto);
console.log(parentProto);//{name: "張三", age: 20, gender: undefined, addr: null, fn: ƒ}
console.log(sonProto);//{name: "張三", age: 20, gender: undefined, addr: {…}, fn: ƒ}
5.3使用自定義深拷貝函數實作原型繼承:
注意:必須在進行深拷貝時是直接将父類進行拷貝後的對象指派給子類,會覆寫掉原有的原型對象上的constructor。這樣當需要通過原型上的contructor 判斷屬于哪個構造函數時,會失效。是以,需要将原型中的構造函數進行追加Son.prototype.constructor = Son;
//繼承:子類繼承父類的所有屬性和行為,父類不受影響
function Parent(name){
this.eyes = 2;
this.name = name;
this.legs = 2;
}
function Son(name){
Parent.call(this,name);
this.hobby = "打籃球";
}
//繼承:隻會繼承父類的構造函數,而不會繼承父類的原型
Parent.prototype.job = function(){
console.log("程式員");
}
//自定義深拷貝實作原型繼承
function deepCopy(obj){
let newObj = Array.isArray(obj)?[]:{};
for(let key in obj){
if(obj.hasOwnProperty(key)){
if(typeof obj[key] == "object"){
newObj[key] = deepCopy(obj[key]);
}else{
newObj[key] = obj[key];
}
}
}
return newObj;
}
Son.prototype = deepCopy(Parent.prototype);
//執行個體化後的對象有構造函數和原型構成,如果隻拷貝原型會丢失構造函數,是以還需要将構造函數傳回
//有時候會通過constructor來判斷執行個體化後的對象是屬于哪個構造函數,如果Son.prototype.constructor = Son;不寫就判斷不了
Son.prototype.constructor = Son;
let parent = new Parent("老張");
let son = new Son("小明");
Son.prototype.job = function(){
console.log("銷售");
}
parent.job();//程式員
son.job();//銷售
重新追加constructor :Son.prototype.constructor = Son;
//如果不寫Son.prototype.constructor = Son;時
console.log(son.constructor);// Object() { [native code] }
Son.prototype.constructor = Son;
console.log(son.constructor);//Son(name){Parent.call(this,name);this.hobby = "打籃球";}
需要追加constructor 的作用:可以通過constructor來判斷,其屬于哪個構造器
//需要追加constructor的作用:可以通過constructor來判斷,其屬于哪個構造器
console.log(son.constructor === Son);//true
let str = 'abc';
console.log(str.constructor === String);//true
5.3組合繼承
- 寫一個空的構造函數;
- 把父級原型指派給這個空的構造函數;
- 再把執行個體化這個空構造函數并指派給自己的原型
function Parent(name){
this.eyes = 2;
this.name = name;
this.legs = 2;
}
function Son(name){
Parent.call(this,name);
}
Parent.prototype.job = function(){
console.log("程式員");
}
//寫一個空的構造函數;
// 把父級原型指派給這個空的構造函數;
// 再把執行個體化這個空構造函數并指派給自己的原型
let Link = function(){};
Link.prototype = Parent.prototype;
Son.prototype = new Link();
//無論哪種方式實作繼承都需要設定會子類的構造函數
Son.prototype.constructor = Son;
let parent = new Parent("張三");
let son = new Son("李四");
Son.prototype.job = function(){
console.log("銷售");
}
parent.job();//程式員
son.job();//銷售
6.原型鍊
構造函數有構造函數自身和原型兩部分組成。而原型本身也是一對對象,是以構造函數的原型又由其自身和原型組成。一直鍊條式進行。
查找順序:先找自身構造函數->再找自身的原型->Object底層的原型->最終找不到傳回undefined
原型鍊是指對象在通路屬性或方法時的查找方式。
1.當通路一個對象的屬性或方法時,會先在對象自身上查找屬性或方法是否存在,如果存在就使用對象自身的屬性或方法。如果不存在就去建立對象的構造函數的原型對象中查找 ,依此類推,直到找到為止。如果到頂層對象中還找不到,則傳回 undefined。
2.原型鍊最頂層為 Object 構造函數的 prototype 原型對象(Object的原型prototype不會再有原型,即Object.prototype再也沒有原型了),給 Object.prototype 添加屬性或方法可以被除 null 和 undefined 之外的所有資料類型對象使用。
如下圖:此處:首先在執行個體化對象parent本身的構造函數Parent上查找name,如果沒有找到,會到執行個體化對象parent的原型上即Parent.prototype上查找,還是沒有找到就到底層Object.prototype上查找,最終都沒有找到就傳回undefined
//原型鍊
function Parent(){
this.name = "張三";
}
Parent.prototype.name = "李四";
Object.prototype.name = "王五";
let parent = new Parent();
//此處:首先在執行個體化對象parent本身的構造函數Parent上查找name,如果沒有找到,會到執行個體化對象parent的原型上即Parent.prototype上查找,還是沒有找到就到底層Object.prototype上查找,最終都沒有找到就傳回undefined
console.log(parent.name);
7.拖拽的邊界需求 :通過繼承來解決
需求:2個div實作拖拽 其中第二個需要設定邊界不能拖出可視區域
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#div1 {
width: 100px;
height: 100px;
background: red;
position: absolute;
top: 20px;
left: 50px;
}
#div2 {
width: 100px;
height: 100px;
background: blue;
position: absolute;
top: 200px;
left: 400px;
}
</style>
</head>
<body>
<div id="div1"></div>
<div id="div2"></div>
<script>
{
//需求:使用繼承實作第二個div不超出邊界
//構造函數一般隻寫屬性
function Drag(ele){
this.ele = ele;
this.mouseDown();
}
Drag.prototype.mouseDown = function(){
//需要将this傳遞到事件裡:指派或者箭頭函數
this.ele.addEventListener("mousedown",ev=>{
//浏覽器相容
let e = ev || window.event;
//擷取初始化滑鼠坐标,直接求出初始化時滑鼠坐标和left/top的值,以免要傳遞多個參數
let x = e.clientX - this.ele.offsetLeft;
let y = e.clientY - this.ele.offsetTop;
this.mouseMove(x,y);
this.mouseUp(x,y);
});
}
//由于move方法也需要共用,是以也寫在原型上
Drag.prototype.setStyle = function(l,t){
this.ele.style.left = l + 'px';
this.ele.style.top = t + 'px';
}
Drag.prototype.mouseMove = function(x,y){
//如果将onmousemove加在document上并使用監聽和匿名函數,則在move方法中的this會指向document,是以需要加在this.ele
//使用監聽時不好傳遞參數
document.onmousemove = ev=>{
let e = ev || window.event;
let left = e.clientX - x;
let top = e.clientY - y;
this.setStyle(left,top);
};
}
Drag.prototype.mouseUp = function(x,y){
document.onmouseup = ev=>{
//清除滑鼠移動事件可以直接使this.ele.onmousemove = "";
document.onmousemove = "";
};
}
let div1 = document.querySelector("#div1");
let drag1 = new Drag(div1);
//給第二個div建立子類繼承父類
function Div2Drag(ele){
//繼承的同時要把所有參數傳遞過去
Drag.call(this,ele);
}
//聲明新的Temp空構造,将父級原型指派給這個空構造的原型
let Temp = function(){};
Temp.prototype = Drag.prototype;
//将示例化後的Temp指派給子級的原型
Div2Drag.prototype = new Temp();
//還原子級原有的構造方法
Div2Drag.prototype.constructor = Div2Drag;
//重寫Div2Drag的滑鼠移動方法
Div2Drag.prototype.mouseMove = function(x,y){
document.onmousemove = ev=>{
let e = ev || window.event;
let left = e.clientX - x;
let top = e.clientY - y;
//限定邊界
left = Math.max(0,left);
top = Math.max(0,top);
left = Math.min(document.documentElement.clientWidth - this.ele.offsetWidth,left);
top = Math.min(document.documentElement.clientHeight - this.ele.offsetHeight,top);
this.setStyle(left,top);
};
}
let div2Drag = new Div2Drag(div2);
}
</script>
</body>
</html>
8.ES6中的類
ES6中的方法會自動加到原型中;
父類的靜态屬性和方法,不能通過執行個體化後的對象擷取;
子類可以繼承父類的靜态屬性和方法,但是子類執行個體化後的對象不能擷取到父類的靜态屬性和方法;
8.1類的寫法
class Person{
height="178cm";
constructor(name,age){
//屬性
this.name = name;
this.age = age;
}
//方法
getName(){
console.log("姓名是:"+this.name);
}
}
let student = new Person("張三",20);
student.getName();
8.2靜态方法和屬性:執行個體不會繼承的屬性和方法,但是子類還是會繼承父類的靜态方法和屬性
class Person{
//靜态方法
static hobby(){
console.log("喜歡籃球");
}
}
//靜态屬性
Person.height = "178cm";
//通過類來調用
Person.hobby();
console.log(Person.height);
8.3類的繼承:extends
class Dad{
name = "張三";
age = 40;
constructor(height){
this.height = height;
}
hobby(){
console.log("喜歡籃球");
}
}
class Son extends Dad{
constructor(height){
//表示父類的構造函數
super(height);
}
}
let son1 = new Son("178cm");
son1.hobby();
console.log(son1.height);
8.4子類重寫父類方法
class Dad{
name = "張三";
age = 40;
constructor(height){
this.height = height;
}
hobby(){
console.log("喜歡籃球");
}
}
class Son extends Dad{
constructor(height){
//表示父類的構造函數
super(height);
}
hobby(){
super.hobby();
console.log("也喜歡足球");
}
}
let son1 = new Son("178cm");
son1.hobby();//喜歡籃球 也喜歡足球
console.log(son1.height);//178cm
8.5使用class繼承實作拖拽
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#div1 {
width: 100px;
height: 100px;
background: red;
position: absolute;
top: 20px;
left: 50px;
}
#div2 {
width: 100px;
height: 100px;
background: blue;
position: absolute;
top: 200px;
left: 400px;
}
</style>
</head>
<body>
<div id="div1"></div>
<div id="div2"></div>
<script>
{
//需求:ES6的繼承,class實作繼承沒有原型的淺拷貝問題
class Drag {
constructor(ele) {
this.ele = ele;
this.mouseDown();
}
mouseDown() {
this.ele.addEventListener("mousedown", ev => {
//浏覽器相容
let e = ev || window.event;
//擷取初始化滑鼠坐标,直接求出初始化時滑鼠坐标和left/top的值,以免要傳遞多個參數
let x = e.clientX - this.ele.offsetLeft;
let y = e.clientY - this.ele.offsetTop;
this.mouseMove(x, y);
this.mouseUp();
});
}
setStyle(l, t) {
this.ele.style.left = l + 'px';
this.ele.style.top = t + 'px';
}
mouseMove(x, y) {
document.onmousemove = ev => {
let e = ev || window.event;
let left = e.clientX - x;
let top = e.clientY - y;
this.setStyle(left, top);
};
}
mouseUp() {
document.onmouseup = function () {
document.onmousemove = "";
}
}
}
let div1 = document.querySelector("#div1");
let drag1 = new Drag(div1);
//給第二個div建立子類繼承父類
class Div2Drag extends Drag {
constructor(ele) {
super(ele);
}
mouseMove = function (x, y) {
document.onmousemove = ev => {
let e = ev || window.event;
let left = e.clientX - x;
let top = e.clientY - y;
//限定邊界
left = Math.max(0, left);
top = Math.max(0, top);
left = Math.min(document.documentElement.clientWidth - this.ele.offsetWidth, left);
top = Math.min(document.documentElement.clientHeight - this.ele.offsetHeight, top);
this.setStyle(left, top);
};
}
}
let div2Drag = new Div2Drag(div2);
}
</script>
</body>
</html>
9.包裝對象
- 除過null,undefined,基本類型都有自己對應的包裝對象:String Number Boolean
- 包裝對象把所有的屬性和方法給了基本類型,然後包裝對象消失
當基本資料類型需要用到包裝類型上的方法時,對自動生成包裝對象。
原理分析:
//包裝對象:String Number Boolean
let str = "a b c";
//基本資料類型調用包裝對象的方法時,原理分析
function mySplit(str,method,arg){
let temp = new String(str);
//最終包裝完後系統會銷毀包裝對象
return temp[method](arg);
}
let res = mySplit(str,"split"," ");
console.log(res);//(3) ["a", "b", "c"]
10.常用方法
javascript中判斷資料類型的四種方法及typeof、instanceof、constructor、toString的詳細講解參考連結:https://blog.csdn.net/liwenfei123/article/details/77978027
- - hasOwnProperty():看是不是對象自身底下的屬性(而不是屬于原型的)。如自定義深拷貝
- - contructor查()看對象的構造函數 可以用來做判斷是屬于哪個構造函數
- - instanceof():對象與構造函數是否在原型鍊上有關系
- typeof():typeof 是一個操作符,其右側跟一個一進制表達式,并傳回這個表達式的資料類型。而對于Date,Array,RegExp等都是傳回原型鍊最頂端的Object。
- - toString()判斷類型; 轉換字元串 進制轉換
10.1hasOwnProperty():看是不是對象自身底下的屬性
function deepCopy(obj){
//判斷參數是對象還是數組,如果是數組就建立新數組進行拷貝,如果是對象就建立新對象進行拷貝
let newObj = Array.isArray(obj)?[]:{};
//通過for...in循環進行拷貝
for(let key in obj){
//hasOwnProperty():看是不是對象自身底下的屬性,而不是原型鍊
//for...in循環會循環原型上的屬性或方法,是以需要使用hasOwnProperty()方法判斷,傳入的對象自身的屬性而不是原型上的屬性,再進行深拷貝
if(obj.hasOwnProperty(key)){
//如果得到的屬性仍然是一個對象,就繼續進行循環
if(typeof obj[key] == "object"){
newObj[key] = deepCopy(obj[key]);
}else{
newObj[key] = obj[key];
}
}
}
return newObj;
}
10.2contructor()檢視對象的構造函數 可以用來做判斷是屬于哪個構造函數:
let str = 'abc';
console.log(str.constructor === String);//true
10.3instanceof():對象與構造函數是否在原型鍊上有關系。檢測的是原型:
//instanceof函數:instanceof 檢測的是原型
let arr = [];
let obj = {};
console.log(arr instanceof Array);//true
console.log(obj instanceof Object);//true
//因為instanceof判斷的是原型鍊上的關系,而數組本身也是複雜資料類型-對象。是以不能使用instanceof來判斷一個數組是否是Array
console.log(arr instanceof Object);//true
//因為字元串str是基本資料類型,沒有原型,而instanceof判斷的是原型,是以會傳回false
let str = "abc";
let str1 = new String("sdf");
console.log(str instanceof String);//false
console.log(str1 instanceof String);//true
console.log(str);
console.log(str1);//String {"sdf"}
10.4typeof() 傳回的是表達式的資料類型:
console.log(typeof arr);//object
console.log(typeof obj);//object
10.5toString()判斷類型;
轉換字元串 進制轉換:用Object.prototype.toString.call(arr)方法判斷的類型最為準确。但是必須通過 call 或 apply 來調用,而不能直接調用 toString()
console.log(Object.prototype.toString.call(arr));//[object Array]
console.log(Object.prototype.toString.call(obj));//[object Object]
console.log(Object.prototype.toString.call(str));//[object String]