本文只爲本身最近看了不少關於es5對象方面的視頻以及書籍,深感前端之路路漫漫其修遠兮,才寫了此篇博客,也是鄙人第一次寫博客,寫的很差你們勿怪。另外本文總結的是es5方面的知識點,就不會用到什麼let,const以及class之類的es6語法,爲了與標題保持一致。我也會在以後總結es6以及typescript方面的知識。還有本文的全部代碼都是親測運行有效後才複製上來的,基本不會存在報錯的狀況,若是有錯誤或者代碼哪兒有問題還望各位大佬多多指教,畢竟我也只是正在前端學習的路上而已,也不是什麼大牛。代碼並不是是書上的源碼,我寫的比較簡單,緣由是照顧一些初學者。若是你在做者的文章中學到了一些新知識不仿給做者點個贊吧,在這裏先謝謝了。javascript
無序屬性的集合(簡單易懂一點,不喜歡扯太複雜,也不喜歡拖泥帶水)html
var obj = {};
複製代碼
var Obj = function(name,age,sex ){
this.name = name;
this.age = age;
this.sex = sex;
}
var newObj = new Obj('張三',24,'男');
console.log(newObj);
console.log(newObj.constructor == Obj);//constructor構造器
console.log(newObj instanceof Object);//instanceof判斷是否爲該對象的子類
console.log(newObj instanceof Obj);
var o = new Object;
Obj.call(o,'李四',26,'女');
console.log(o.name);
複製代碼
var obj = function(name,age,sex){
var o = new Object() || {};//new寫煩了,試了一下{}建立,也沒有問題。
o.name = name;
o.age = age;
o.sex = sex;
return o;
}
var newObj = obj('張三',24,'男');
console.log(newObj);
複製代碼
var Obj = function(){};
Obj.prototype.name = '張三';
Obj.prototype.age = 24;
Obj.prototype.sex = '男';
var o = new Obj;
console.log(o.name);
console.log(Obj.prototype.isPrototypeOf(o));//判斷對象的原型prototype是否指向Obj;
console.log(Object.getPrototypeOf(o)==Obj.prototype);//同Obj.prototype
console.log(Obj.hasOwnProperty('name'));//在該對象實例中是否有該屬性,有就返回true
console.log('name' in Obj);//在該對象中是否有該屬性,不論是原型上仍是實例上,有就返回true
console.log(o.hasOwnProperty('name'));
console.log('name' in o);
複製代碼
更簡單的方式:前端
var Obj = function(){};
Obj.prototype={
name : '張三',
age : 24,
sex : '男'
}
複製代碼
var Obj = function(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
if(typeof this.sayName != 'function'){
Obj.prototype.sayName=function(){
console.log(this.name);
}
}
}
var o = new Obj('張三',24,'男');
o.sayName();
複製代碼
var Obj = function(){
var values = new Array();
values.push.apply(values, arguments);
values.toPipedString = function(){
return this.join("|");
};
return values;
}
var o = new Obj("red", "blue", "green");
console.log(o.toPipedString());
複製代碼
var Obj = function(name,age,sex){
var o = new Object();
o.getName = function(){
console.log(name);
}
return o;
}
var newObj = Obj('張三',24,'男');
newObj.getName();
複製代碼
var Obj = function(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
}
Obj.prototype = {
getName:function(){
console.log(this.name);
}
}
var o = new Obj('李四',24,'男');
o.getName();//李四
複製代碼
前言:衆所周知對象有三個特性,也是比較重要的特性——封裝、繼承、多態。java
注:文檔開頭已註明了基本概念es6
var Obj = function(name){
var name = name;//私有變量
this.age = 26;//公有屬性
this.getName = function(){//特權方法
return name;
};
Introduce = ()=>{//私有方法
console.log(this);
//若是不用es6的箭頭函數,那麼this指向的是window,this.age始終未定義,es6箭頭函數指向它所在的父級做用域,this.age就會獲取到26的值(實在不得已破了個例)
return name + '今年' + this.age + '歲了';
};
this.getIntroduce = function(){//公有方法
return Introduce;
}
}
var o = new Obj('張三');
console.log(o);//Obj{age: 26, getName: ƒ}
console.log(o.name);//undefined
console.log(o.getName());//張三
// console.log(o.Introduce());//會報錯
var newGetIntroduce = o.getIntroduce();
console.log(newGetIntroduce());
複製代碼
var Obj = function(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
var newObj1 = new Obj('張三',24,'男');
var newObj2 = new Obj('李四',18,'女');
console.log(newObj1);
console.log(newObj2);//多態指得就是調用同一個函數產生不一樣對象的這種特性
複製代碼
var Obj = function(){
var name = '張三';
this.getName = function(){
return name;
};
};
var newObj = function(){};
newObj.prototype = new Obj();//實現繼承
var O = new newObj();
console.log(O.getName());
複製代碼
var Obj = function(name){
this.name = name;
};
var newObj = function(){
Obj.call(this,'張三');
};
var O = new newObj();
console.log(O.name);//張三
複製代碼
var Obj = function(){
this.name = '張三';
}
Obj.prototype.getFn = function(){
return this.name;
}
var newObj = function(){
Obj.call(this);//繼承Obj函數內部this上的值
}
newObj.prototype = new Obj();//繼承Obj函數原型鏈上的值
var o = new newObj();
console.log(o.getFn());//張三
複製代碼
var newObj = function(Obj){
var o = Object.create(Obj);//實現繼承
o.getName = function(){
return o.name;
}
return o;
}
var Obj = {
name:'張三'
}
var Obj1 = newObj(Obj);
console.log(Obj1.getName());//張三
複製代碼
var Obj = function(){
this.name = '張三';
}
Obj.prototype.getName = function(){
return this.name;
}
var newObj = function(){
Obj.call(this);//獲取對象中的自身屬性值
}
var inherit = function(Obj,newObj){
var prototype = Object.create(newObj.prototype);//獲取子類的原型
prototype.constructor = Obj;//將父對象放置在子對象的constructor下
Obj.prototype = prototype;//將父對象的原型賦值給子對象的原型
}
inherit(newObj,Obj);
var O = new newObj();
console.log(O.getName());//張三
複製代碼
//call()
var Obj = function(){
this.name = '張三';
}
var newObj = function(){
Obj.call(this);//實現繼承
this.getName = function(){
return this.name;
}
}
var o = new newObj();
console.log(o.getName());//張三
//apply()
var Obj = function(){
this.name = '張三';
}
var newObj = function(){
Obj.apply(this);//實現繼承
this.getName = function(){
return this.name;
}
}
var o = new newObj();
console.log(o.getName());//張三
複製代碼
var Obj = function(){
this.name = '張三';
}
var newObj = function(){
this.Obj = Obj;
this.Obj();//實現繼承
delete this.Obj;
this.getName = function(){
return this.name;
}
}
var o = new newObj();
console.log(o.getName());
複製代碼
var inherit = function(o){//實現繼承的函數
function F(){};
F.prototype = o;
return new F();
}
var Obj = {
name:'張三'
}
var newObj = inherit(Obj);
console.log(newObj.name);//張三
複製代碼
console.log(this);//window
複製代碼
function fn(){
console.log(this);//Window
};
fn();
複製代碼
var Obj = {
_this : function(){
return this;
}
}
console.log(Obj._this());//Obj
複製代碼
//html部分
<div id="v1" style="width: 200px; height: 200px;background-color: #666;position: absolute;top:50%;left: 50%;transform:translate(-50%,-50%);"></div>
//js部分
var v1 = document.getElementById('v1');
v1.onclick = function(){
console.log(this);
}//返回結果爲html部分所有內容
複製代碼
小結:綜上所述,this通常狀況下指向其執行的上下文環境(es6箭頭函數中this指向其父級做用域)算法
function fn(){
console.log(this);
};
var Obj = {
name:'李四',
getThis:function(){
console.log(this);
}
}
fn();//Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
fn.call(Obj);//{name: "李四", getThis: ƒ}
複製代碼
function fn(){
console.log(this);
};
var Obj = {
name:'李四',
getThis:function(){
console.log(this);
}
}
fn();//Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
fn.apply(Obj);//{name: "李四", getThis: ƒ}
複製代碼
function fn(){
console.log(this);
};
var Obj = {
name:'李四',
getThis:function(){
console.log(this);
}
}
fn();//Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
fn.bind(Obj)();//{name: "李四", getThis: ƒ}
複製代碼
做用域:在es5中有全局做用域和函數做用域。
全局做用域:在函數做用域中,能訪問到全局做用域中的變量typescript
var num = 1;
function fn(){
console.log(num);//1
}
fn();
複製代碼
函數做用域:在函數中的變量,在函數外部的全局做用域中是訪問不到的json
function fn(){
var num = 1;
console.log(num);//1
}
fn();
console.log(num);//報錯:num is not defined
複製代碼
一種比較特殊的狀況:若變量沒有用關鍵字進行聲明,那麼默認是全局變量。數組
function fn(){
num = 1;
}
fn();
console.log(num);//1
//另外說一下,這種寫法在嚴格模式下會報錯。
複製代碼
這種寫法雖然能夠能在全局做用域中拿到函數中的變量,但通常不推薦這麼寫。
在es5中沒有塊級做用域,然而在許多狀況下會產生必定的問題:瀏覽器
for(var i=0;i<2;i++){
console.log(i);//0,1;
}
console.log(i);//2
複製代碼
在尚未let和const的塊級做用域時,咱們的前輩已經想到了用私有做用域來模仿塊級做用域:
(function(){
for(var i=0;i<2;i++){
console.log(i);//0,1;
}
})();
console.log(i);//i is not defined
複製代碼
這樣外界在for循環結束後就訪問不到i變量了。
小結:若是要經過一個標準的方法訪問函數中的變量的話,推薦使用閉包。
function fn(){
var name = '張三';
var age = 20;
return function(){
return name + '今年' + age + '歲了';
}
}
var newFn = fn();
console.log(newFn());//張三今年20歲了
複製代碼
function fn(n){
if(n <= 1){
return 1;
}else{
return n*fn(n-1);
}
}
console.log(fn(10));//3628800
複製代碼
3.遞歸的優缺點:
優勢:在樹的前序,中序,後序遍歷算法中,遞歸的實現明顯要比循環簡單得多。
缺點:
let a = {
age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age)//1
複製代碼
(2). 經過展開運算符 ... 來實現淺拷貝:
let a = {
age: 1
}
let b = { ...a }
a.age = 2
console.log(b.age) // 1
複製代碼
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE
複製代碼
缺點:會忽略 undefined、不能序列化函數、不能解決循環引用的對象(會忽略es6的symbol)
前言:若是有沒有列舉到的屬性以及方法歡迎補充
先看一下基本目錄吧:
(這是官方解釋,後面我會根據本身的理解給你們簡單的解釋一下)
var Obj = function(name){
this.name = name;
this.isShow = true;
};
Obj.prototype.age = 23;
Obj.prototype.getName = function(){
if(this.isShow){
console.log('個人名字是' + this.name + ',今年' + this.age + '歲');
}
}
var newObj = new Obj('張三');
newObj.getName();//個人名字是張三,今年23歲
複製代碼
var Obj = function(name){
this.name = name;
}
var newObj = new Obj('張三');
console.log(newObj.constructor);//ƒ (name){this.name = name; }
複製代碼
var Obj = function(name){
this.name = name;
}
var newObj = new Obj('張三');
var copy = Object.assign({},newObj);
console.log(copy);//{name: "張三"}
複製代碼
也許你會好奇:這個爲何叫淺拷貝,跟深拷貝有什麼區別呢?那麼讓我用下面的例子爲你解釋一下吧!
var Obj = function(name){
this.name = name;
var age = 24;
this.getAge = function(){
return age;
}
}
Obj.prototype.getName = function(){
return this.name;
}
var newObj = new Obj('張三');
var copy = Object.assign({},newObj);
console.log(newObj);//{name: "張三", getAge: ƒ},你點開__proto__是能找到getName的方法的
console.log(copy);//{name: "張三", getAge: ƒ}你點開__proto__是找不到getName的方法的
複製代碼
小結:淺拷貝只是將對象中的屬性以及方法進行拷貝,而對象原型上的屬性以及方法是沒有進行任何拷貝的。
(2). 合併對象:
var Name = {
name:'張三'
}
var Age = {
age:24
}
var Sex = {
sex:'男'
}
var newObj = Object.assign({},Name,Age,Sex);
console.log(newObj);//{name: "張三", age: 24, sex: "男"}
複製代碼
(3). 合併具備相同屬性的對象:(後者覆蓋前者)
var Name = {
name:'張三'
}
var Age = {
name:'李四',
age:24
}
var Sex = {
name:'王五',
age:25,
sex:'男'
}
var newObj = Object.assign({},Name,Age,Sex);
console.log(newObj);//{name: "王五", age: 25, sex: "男"}
複製代碼
(4). 拷貝訪問器:
var Obj = {
name:'張三',
get age(){
return 25
}
}
var copy = Object.assign({},Obj);
console.log(copy);//{name: "張三", age: 25}
複製代碼
var Obj = {
name:'張三',
isShow:false,
getName:function(){
if(this.isShow){
console.log('個人名字叫' + this.name);
}
}
}
var newObj = Object.create(Obj);
newObj.isShow = true;
newObj.getName();//個人名字叫張三
複製代碼
語法:Object.defineProperties(obj, props)
其中props:
(1). configurable:可否經過delete刪除屬性從而從新定義屬性,可否修改屬性的特性,或者可否把屬性修改成訪問器屬性
(2). enumerable:表示可否經過for-in循環返回屬性
(3). value:與屬性關聯的值。能夠是任何有效的JavaScript值(數字,對象,函數等)。
(4). writable:表示可否修改屬性值
(5). get:獲取值。
(6). set:設置值。
var Obj = {sex:'男'};
Object.defineProperties(Obj, {
'name':{
configurable:true,
enumerable:true,
value:'張三',
writable:true
},
Sex:{
get:function(){
return this.sex;
},
set:function(data){
this.sex = data;
}
}
});
Obj.Sex = '女';
console.log(Obj.sex);//女
複製代碼
對象中的數據屬性行爲特性:
注:修改如下4中數據屬性行爲的方法:Object.defineProperty
(1). configurable:可否經過delete刪除屬性從而從新定義屬性,可否修改屬性的特性,或者可否把屬性修改成訪問器屬性
var obj = {
age:'24',
sex:'男'
};
Object.defineProperty(obj,'name',{
configurable:true,//規定該屬性值是否能被刪除,若是爲true則能被刪除,若是爲false則不能被刪除
enumerable:false,
//規定該屬性是否能夠for-in遍歷,true則能經過for-in打印出name的值,若是爲false則打印不出來name的值
writable:true,//若是爲true,第二個name打印爲李四,若是爲false第二個name打印爲張三
value:'張三'//設置name屬性的屬性值
})
delete obj.name;
console.log(obj);
複製代碼
(2). enumerable:表示可否經過for-in循環返回屬性
var obj = {
age:'24',
sex:'男'
};
Object.defineProperty(obj,'name',{
enumerable:false,
//規定該屬性是否能夠for-in遍歷,true則能經過for-in打印出name的值,若是爲false則打印不出來name的值
writable:true,//若是爲true,第二個name打印爲李四,若是爲false第二個name打印爲張三
value:'張三'
})
for(var key in obj){
console.log(obj[key]);
}
console.log(obj);
複製代碼
(3). writable:表示可否修改屬性值
var obj = {};
Object.defineProperty(obj,'name',{
writable:true,//若是爲true,第二個name打印爲李四,若是爲false第二個name打印爲張三
value:'張三'
})
console.log(obj.name);
obj.name = '李四';
console.log(obj.name);
複製代碼
(4). value:包含這個屬性的數據值
var obj = {};
Object.defineProperty(obj,'name',{
value:'張三'
})
console.log(obj.name);//張三
複製代碼
訪問器屬性:
注:前兩種方法跟對象中的數據屬性行爲特性中的同樣,就很少贅述了
(1). configurable:規定該屬性值是否能被刪除
(2). enumerable:規定該屬性是否能夠for-in遍歷
(3). get:讀取屬性時調用的函數
(4). set:寫入屬性時調用的函數
var obj = {
_name:'李四'
};
Object.defineProperty(obj,'name',{
get:function() {
return this._name;
},
set:function(newName){
if(newName){
this._name = newName;
}
}
})
obj.name = '';
console.log(obj.name);//李四
複製代碼
var Obj = {
name:'張三',
id:1
};
//for(var [key,value] of Object.entries(Obj)){
//console.log(key + ',' + value);
//}//name,張三 id,1
console.log(Object.entries(Obj))//[[name,張三],[id,1]];
複製代碼
注:此處用for-in會打印出對象的key值爲0和1,然而value打印出來倒是未定義。
var Obj = {
name:'張三',
id:1
};
//for(var value of Object.values(Obj)){
//console.log(value);
//}//張三 1
console.log(Object.values(Obj));//張三 1
複製代碼
var Obj = {
name:'張三',
id:1
};
//for(var key of Object.keys(Obj)){
//console.log(key);
//}//name id
console.log(Object.keys(Obj));//name id
複製代碼
var Obj = {
name:'張三',
id:1
}
Object.freeze(Obj);
Obj.name = '李四';
Obj.sex = '女';
console.log(Obj);//{ name: "張三", id: 1 }
複製代碼
注:該方法可以讓對象變成只可讀不可寫的類型,能夠有效地防止別人在不須要修改的對象上添加屬性。
11. Object.fromEntries() 方法把鍵值對列表轉換爲一個對象。
var arr = [['name','張三'],['id',1]];
console.log(Object.fromEntries(arr));//{ name: "張三", id: 1 }
複製代碼
var Obj = {
name:'張三'
};
console.log(Object.getOwnPropertyDescriptor(Obj,'name'));
//{ value: "張三", writable: true, enumerable: true, configurable: true }
複製代碼
var Obj = {
name:'張三',
id:1
}
console.log(Object.getOwnPropertyDescriptors(Obj));
//name: {value: "張三", writable: true, enumerable: true, configurable: true}
//id: {value: 1, writable: true, enumerable: true, configurable: true}
複製代碼
var Obj = {
name:'張三',
id:1
}
console.log(Object.getOwnPropertyNames(Obj));
複製代碼
var obj = {};
var a = Symbol("a");
var b = Symbol.for("b");
obj[a] = "akdfj";
obj[b] = "asdkflj";
var newObj = Object.getOwnPropertySymbols(obj);
console.log(newObj.length); // 2
console.log(newObj) // [Symbol(a), Symbol(b)]
console.log(newObj[0]) // Symbol(a)
複製代碼
var Obj = {};
console.log(Object.getPrototypeOf(Obj));
/**{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}**/
複製代碼
console.log(Object.is([],[]));//false
console.log(Object.is({},{}));//false
console.log(Object.is(NaN,NaN));//true
console.log(Object.is(NaN,0/0));//true
console.log(Object.is("",false)); //false
複製代碼
注:只有左右兩側運行的值與其指向也徹底相同時纔會返回true
var Obj = {
name:'張三',
id:1
}
Object.freeze(Obj);
console.log(Object.isExtensible(Obj));//false
複製代碼
var Obj = {
name:'張三',
id:1
}
Object.freeze(Obj);
console.log(Object.isFrozen(Obj));//true
複製代碼
var Obj = {};
Object.preventExtensions(Obj);//讓空對象變成不可擴展對象
console.log(Object.isSealed(Obj));//true;
複製代碼
(2).非空對象變成密封對象:
var Obj = {
name:'張三',
}
Object.preventExtensions(Obj);//讓對象變成不可擴展對象
Object.defineProperty(Obj, "name", { configurable: false });//若是是非空對象必須將自身屬性變成不可配置才能成爲一個密封對象
console.log(Object.isSealed(Obj));
複製代碼
var Obj = {
name:'張三'
}
Object.preventExtensions(Obj);
console.log(Object.isExtensible(Obj));//false
複製代碼
var Obj = {
name:'張三'
}
console.log(Obj.hasOwnProperty('name'));//true
複製代碼
function Bar() {}
function Baz() {}
Baz.prototype = Object.create(Bar.prototype);
var baz = new Baz();
console.log(Bar.prototype.isPrototypeOf(baz));
複製代碼
var Obj = {
name:'張三'
}
console.log(Obj.propertyIsEnumerable('name'));//true
複製代碼
var Obj = {
name:'張三'
}
console.log(Obj.toLocaleString());//[object Object]
複製代碼
注:此方法的返回結果不太懂。
var Obj = {
name:'張三'
}
console.log(Obj.toString());//[object Object]
複製代碼
注:JSON.stringify(Obj)可將對象轉化成json字符串
//Number
var num = 1;
console.log(num.valueOf());//1
//String
var str = '我';
console.log(str.valueOf());//我
//Boolean
var bool = false;
console.log(bool.valueOf());//false
//以此類推
複製代碼
var Obj = {
name:'張三'
}
Object.seal(Obj);
console.log(Object.isSealed(Obj));//true
複製代碼
如何遍歷對象原型上的屬性及方法名?
var obj = function(){};
obj.prototype.name = '張三';
obj.prototype.id = 1;
obj.prototype.getName = function(){
return this.name;
}
var newObj = new obj;
console.log(newObj);
for(var key in newObj){
console.log(key);
}//name,id.getName
複製代碼
如何實現數據的雙向綁定?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>雙向綁定</title>
</head>
<body>
<h1 id="title">hello</h1>
<input type="text" id="inp">
<script>
var input = document.getElementById('inp');
var title = document.getElementById('title');
input.oninput = function(e){
title.innerHTML = e.target.value || this.value;
}
//監聽input及title值的變化
function monitor(Obj,Objkey){
Object.defineProperty(Obj,Objkey,{
get:function(){
return input.value;
},
set(val){
title.innerHTML = val;
input.value = val;
}
})
}
monitor(title,'inner');
title.inner = '123';
// monitor(input,'val');
// input.val = '456';
</script>
</body>
</html>
複製代碼
如何實現對象轉數組?
var Obj = {
name:'張三',
id:1
}
function toArr(Obj){
return Object.entries(Obj).flat();
}
console.log(toArr(Obj));//["name", "張三", "id", 1];
複製代碼
做者始終堅信實踐是檢驗真理的惟一標準,不論是報錯也好仍是這些零散的知識點也好,全部的代碼都只有你本身試過才知道有沒有效,沒有試過的代碼靠猜是猜不出來的,代碼的對錯瀏覽器會告訴你答案的!另外以上的知識點不少概念都是我本身理解了以後用本身的話表述的,若是有說錯的地方,還望各位大佬指點一二。