本文只为本身最近看了不少关于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];
复制代码
做者始终坚信实践是检验真理的惟一标准,不论是报错也好仍是这些零散的知识点也好,全部的代码都只有你本身试过才知道有没有效,没有试过的代码靠猜是猜不出来的,代码的对错浏览器会告诉你答案的!另外以上的知识点不少概念都是我本身理解了以后用本身的话表述的,若是有说错的地方,还望各位大佬指点一二。