Object对象
原型链
-
在类中定义的方法存储在原型链中,对象实例化后,通过点语法增加的方法保存在该实例化对象中,是该实例化对象独有的方法
class Box{ constructor(){ } play(){ } run(){ } } var b=new Box() b.abc=function(){ } console.log(b);
-
类继承基类时,当前类的原型中存在基类的原型,实例化对象后,通过点语法添加的属性属于该实例化对象独有。
class Box{ constructor(){ } play(){ } run(){ } } class Ball extends Box{ constructor(){ super(); } action(){ } } var e=new Ball(); e.a=10; console.log(e);
-
万物皆对象
-
具有属性和方法的都是对象
-
所有的对象都有原型链
//数组 var arr=[1,,2,4] console.log(arr); //日期对象 var date=new Date(); console.dir(date); //正则 var reg=/a/; console.dir(reg); //DOM元素 var div=document.createElement("div"); console.dir(div); //Symbol var s=Symbol(); console.log(s);//不能显示 console.log(s.__proto__);//可以显示 //字符串 var str="aaa"; console.log(str.__proto__);
-
-
原型
- 类实例化新对象时会将类中的对象也赋给新对象,所以在类中的方法都存储在–proto–原型中,而实例化对象增加的方法,是属于实例化对象个体的,不会存储在原型中
- 类中constructor()构造函数中的属性和方法都是在创建实例化对象时产生的,属于实例化对象自身的属性和方法,不是存储在–proto–中
- 对象中的–proto–
- 任何对象都可以调用其原型下的属性和方法
-
所有的对象都会继承Object对象,都会存在Object的原型–proto–
- DOM对象继承了多层基类,在改动DOM对象时,会将原型链进行重绘,耗费性能
-
特殊处理的对象(五种)
- 存储在栈中的类型也是对象,调用方法时,会去堆中调用响应的方法
- String
- Number
- Boolean
- null
- undefined
-
对象的创建
-
字面量创建
var obj={a:1}
-
构造函数创建法
- 对象中的key必须是String或Symbol类型,如果不是就会隐式转换为String类型
var obj= new Object(); obj.a=10; var c="c"; obj[c]=20; console.log(obj);
-
对象增加属性
obj.b=10;//b是字符串 var c="c"; obj[c]=20;//c是变量 //key为对象 var o={a:2}; obj[o]=10; console.log(obj[{b:3}]);//10 //key为数组 var arr=[0]; obj[arr]=100; console.log(obj[0]); console.log(obj[0,12]);
- 对象在转换为字符串时会转换为[Object Object],所以所有的对象都会转换成相同的字符串
- 数组在转换为对象时,会将数组的每一项以,连接,转换成一个字符串,作为key值
-
以原有对象为原型创建新对象
//以o为原型创建o1 var o={a:1}; var o1=Object.create(o); var o2=Object.create(o);
console.log(o,o1,o2)
o.a=10;
console.log(o,o1,o2)
o1.b=10;
o2.c=10;
console.log(o,o1,o2)
o1.a=10;
o2.a=11;
console.log(o,o1,o2)
console.log(o1.proto===o);- 原型指向原有对象,使用原有对象的引用地址,当原有对象的属性或方法改变时,新对象的原型也会发生改变,新对象可以使用原有对象的属性和方法 - 当设置对象属性时,直接设置的是对象的自身属性(对象属性),获取时首先查看该对象有没有这个名称的对象属性,如果有,直接返回这个属性值;如果没有向下查找紧邻的原型链中的属性,是否具有该属性名,查找到距离该对象__最近__的原型链中的属性名后返回其值。 - 以相同原型创建的新对象是独立存在的,没有关系;原型改变时会影响所有新对象 - 任何对象都能通过--proto--修改原型链的属性
-
-
对象创建时的特征
-
对象的属性下使用this,this指向对象外的this指向,在对象的方法中使用this,this指向该对象
var c=0; var obj={ a:1, b:function(){ console.log(this.a); }, [c]:10, c:100, d:this.c } //执行obj.b()时,obj已经创建完成,this指obj obj.b();//1 //对象属性中的this,对象还没有创建完成,this还没有形成,所以this指向对象外this指向 console.log(obj.d);//0
-
对象没有长度length
-
对象的assign
- 对象的浅复制
-
仅把第一层的属性复制到新对象中,如果第一层的属性值是引用类型,则会把引用地址复制
-
o={…o1}
- …是解构o1
- 将o1的所有属性解构产生新对象赋值给了o
- 地址会发生改变
var o5=o4={h:10}; o4={...o1,...o2,...o3}; console.log(o4===o5);//false 引用地址发生了改变
-
obj=Object.assign(新对象,原对象1,原对象2,…)
- 将一个或者多个对象中的可枚举属性复制到第一个参数对象中,如果后面的对象的属性与前面对象的属性相同,会覆盖前面的对象的属性
- 浅复制,仅能把第一层的属性复制到新对象上,如果第一层的属性值是引用类型,则会把引用地址赋值
var o={ a:1, b:2, c:{ d:1 } } var o1=Object.assign({},o); console.log(o1); o.c.d=10; console.log(o1);
- 原对象中增加复制的属性,引用地址不改变
var o1={a:1,b:2,c:3}; var o2={d:4,e:5,f:6}; var o3={a:7,e:8,c:9}; var o0=o={h:10}; Object.assign(o,o1,o2,o3); console.log(o===o0);//true
-
对象的属性相关方法
-
Object.defineProperty(对象,属性名,该属性的描述对象)
-
属性的描述对象
-
configurable: true,//该属性是否可以删除,并且该属性的描述对象是否可以更改,默认false
-
enumerable: true,//该属性是否可以枚举,默认false
-
writable: true,//该属性是否可写(不是只读),默认false
-
value: 10,//该属性的值
var obj={}; Object.defineProperty(obj,"a",{ configurable:true,//可删除 enumerable:true,//可枚举 writable:true,//可删除 value:2//值为2 }) //也可写成以下写法 Object.defineProperty(obj,"b",{ configurable:true, enumerable:true, set:function(_v){}, get:function(){} }) console.log(obj);
- writable和value与set和get冲突,不能同时设置
-
Object.defineProperties(对象,属性名,该属性的描述对象)
- 同时设置多个属性
Object.defineProperties(obj,{ a:{ enumerable:false, writable:true, configurable:true, value:20 }, b:{ writable:true, configurable:true, value:function(){ } }, c:{ configurable:true, value:100 } })
-
Object.getOwnPropertyNames(对象)
- 获取对象的所有对象属性名
Object.defineProperties(obj,{ a:{ value:1 }, b:{ enumerable:true, value:2 }, c:{ writable:true, value:3 } }); obj.d=10; obj.e=100; var arr=Object.getOwnPropertyNames(obj); console.log(arr); for(var i=0;i<arr.length;i++){ console.log(arr[i],obj[arr[i]]); var disc=Object.getOwnPropertyDescriptor(obj,arr[i]); console.log(disc); }
-
Object.getOwnPropertyDescriptor(对象,属性)
- 获取属性的描述对象
- 返回数组
var disc=Object.getOwnPropertyDescriptor(obj,"a");
-
Object.freeze()
-
冻结
-
对象属性不可修改,不可删除
-
可以将该对象下所有属性转换为常量
-
冻结数组
- 数组的每一项不可修改
var arr=[1,2,3,4]; Object.freeze(arr); arr[2]=100; console.log(arr);
-
冻结对象
- 所有属性不可修改、不可删除
- 将该对象下所有属性正式转换为常量
Object.freeze(obj);
-
冻结函数
- 函数内部的数据或方法不可修改
-
-
Object.is(a,b)
- 判断某个内容是不是指定值
- 返回true/false
- 类似于=的比较,但是NaN=NaN,此时等同于isNaN()
- 判断某个内容是不是指定值
-
Object.isExtensible(obj)
- 判断对象是否可以扩展
- 冻结后,不可扩展,不可以增加新属性
- 判断对象是否可以扩展
-
Object.isFreeze(obj)
- 判断对象是否冻结
-
Object.hasOwnProperty(“a”)
-
判断当前对象的对象属性,原型链上的属性不属于对象属性
var o={a:1,b:2}; var o1=Object.create(o); o1.c=10; var o2=Object.create(o1); console.log(o1.hasOwnProperty("a")); console.log("a" in o1)
- 原型链上的属性不是该对象的属性
- 通过in判断时,可判断原型链上的属性
-
-
obj.isPrototypeOf(o)
-
判断对象是否在指定对象的原型链下,指定对象的父类中是否有当前对象
-
o对象的父类是否有obj
var o={a:1,b:2}; var o2=Object.create(o1); console.log(o.isPrototypeOf(o2)); class Box{ constructor(){ } play(){ if(parent.constructor===String) parent=document.querySelector(parent); if(HTMLElement.isPrototypeOf(parent.constructor)) parent=document.body; parent.appendChild(this.elem); } } class Ball extends Box{ constructor(){ super(); } run(){ } } console.log(Box.isPrototypeOf(Ball));//true var b=new Ball(); console.log(Box.isPrototypeOf(b.constructor));//true console.log(document.documentElement); var div=document.createElement("div"); console.log(HTMLElement.isPrototypeOf(div.constructor));//判断是不是HTML标签
-
-
obj.propertyIsEnumerable(属性)
- 判断该对象的某个属性是否是不可枚举属性
- 空类型不属于对象
-
instanceof
- 类别
class Box{ constructor(){ } play(){ if(parent.constructor===String) parent=document.querySelector(parent); if(HTMLElement.isPrototypeOf(parent.constructor)) parent=document.body; parent.appendChild(this.elem); } } class Ball extends Box{ constructor(){ super(); } run(){ } } var b=new Box(); console.log(b instanceof Box);//true console.log(b instanceof Ball);//false console.log(b.constructor===Box);//true
-
null不属于对象类型
-
但是typeof null === Object
var b=null; console.log(typeof b); console.log(b instanceof Object); console.log(b.constructor===Object);//报错
-
函数
-
函数的执行
-
call/apply
- 可以改变函数中this的指向,当传入对象参数时,函数中的this会指向参数,如果参数不是对象,会将参数转换成对象
- call的第一个参数是函数中this的指向,后面会按顺序带入参数
- apply只有两个参数,第一个参数是函数中的this指向的对象,第二个参数是函数所需的所有参数的数组/列表
function fn(a,b,c){ console.log(this,a+b+c); } var obj={a:1}; fn.call("5"); fn.call(obj,1,2,3); fn.apply(obj,[1,2,3]);
- 只要调用call和apply,函数就会执行
- 所有的回调函数如果需要替换this都不能使用call和apply,需要使用bind()方法
var obj={a:1} setTimeout((function(){ console.log(this); }).call(obj),1000);//使用call,不能延时执行,因为回调函数被立即执行 var obj={ a:1, b:function(){ document.addEventListener("click",this.clickHandler.call(this));//此时直接执行clickHandler,点击时没有效果 }, clickHandler:function(e){ console.log(this); } } obj.b();
function fn(a,b,c){ console.log(this,a+b+c); } fn();//this window var obj={a:1}; fn.call(obj);//将obj带入到函数替代函数中this的指向,原有的this会被指向obj fn.apply(obj);//和call一样
- 获取数组中的最大最小值
var arr=[1,2,3,4,5]; var min=Math.min.apply(null,arr); var max=Math.max.apply(null,arr); console.log(min,max);
- 重写Math的min/max函数
var Maths={ min:function(){ if(arguments.length===0) return; var min=arguments[0]; if(arguments.length===1) return arguments[0]; for(var i=0;i<arguments.length;i++){ min=min>arguments[i]?arguments[i]:min; } return min; }, max:function(){ if(arguments.length===0) return; var max=arguments[0]; if(arguments.length===1) return arguments[0]; for(var i=0;i<arguments.length;i++){ max=max<arguments[i]?arguments[i]:max; } return max; } } var arr=[1,2,3,4,5]; console.log(Maths.min.apply(null,arr),Maths.max.apply(null,arr));
- 重写Array的slice()方法
class Arrays{ constructor(){ } slice(start,end){ if(start === undefined) start=0; if(end===undefined) end=this.length; var arr=[]; for(var i=start;i<end;i++){ arr.push(this[i]); } return arr; } } var arr=new Arrays(); console.log(arr.slice.call(document.getElementsByTagName("div")));
-
bind()
- 绑定要传入的参数,不会执行函数
- 调用bind()函数后,会返回一个新的函数,函数中所有的this都会指向参数
function fn(){ console.log(this); } var f=fn.bind({a:1}); fn();//window f();//{a:1}
- 进行回调的传参,this就是bind()绑定的内容
- 在侦听事件时,绑定的函数已经被更改了,每一次调用事件侦听的函数都会重新生成一个新的函数,所以无法删除侦听事件
- 需要将事件侦听的函数单独保存出来,再进行删除
var obj={a:1}; setTimeout((function(){ console.log(this); }).bind(obj),1000)//1秒后打印{a:1} var obj={ a:1, b:function(){ document.addEventListener("click",this.clickHandler.bind(this)); }, clickHandler:function(e){ console.log(this); document.removeEventListener("click",this.clickHandler);//这种写法,没有办法删除事件 } } obj.b(); var obj={a:1}; setTimeout((function(){ console.log(this); }).bind(obj),1000)//1秒后打印{a:1} var obj={ a:1, b:function(){ this.handler=this.clickHandler.bind(this); document.addEventListener("click",this.handler);//这种写法,没有办法删除事件 }, clickHandler:function(e){ console.log(this); document.removeEventListener("click",this.handler) } } obj.b();
-
-
this
-
ES5非严格模式,全局中的this和函数中的this都指向window
console.log(this); function fn(){ console.log(this); } fn();
-
ES5严格模式,ES6全局中this仍然指向window,函数中this指向undefined
"use strict"; console.log(this); function fn(){ console.log(this); } fn();
-
对象中的this
-
对象中的函数的this指向当前对象自身obj
-
对象中的属性中的this指向对象外this的指向(对象外上下文环境中this的指向)
- 对象没有创建完成时,this还没有生成,this就指向对象外this的指向
var obj={ a:1, b:function(){ console.log(this);//this不会因为变量引用改变而改变 // this指向当前对象自身obj console.log(obj.a);//变量会发生引用改变 }, c:this.a //this指向对象外this的指向 //对象没有创建完成时,this还没有生成,this就指向对象外this的指向 }
-
-
回调函数中的this
-
如果直接执行的回调函数,this指向最外层的window
-
如果通过arguments直接使用参数执行函数,this则指向执行当前函数的arguments
-
如果回调函数通过call/apply/bind重新指向了新的对象时,this就是这个重新指向的新对象
var obj = { a: function () { console.log(this,"____"); var self=this; function fn1(fn) { // fn(); // arguments[0]();//arguments fn.call(self); } function fn2() { console.log(this);//window 回调函数中 } fn1(fn2); }, };
-
-
事件中的this
- 事件中是特殊的回调函数
- addEventListener()侦听事件时,this指向事件的侦听对象(只要不使用箭头函数,就都是侦听对象) e.currentTarget
- IE8,attatch()侦听事件时,this指向window
var obj={ b:1, a:function(){ // 特殊的回调函数 document.addEventListener("click",this.clickHandler); }, clickHandler:function(e){ console.log(this);//事件侦听的对象 e.currentTarget } } var obj={ b:1, a:function(){ // console.log(this); // 特殊的回调函数 document.addEventListener("click",this.clickHandler); // document.attachEvent("onclick",this.clickHandler); }, clickHandler:function(e){ console.log(this===document);//addEventListener事件侦听的对象 e.currentTarget console.log(this===window);//IE8 attachEvent侦听事件时,this指向window } } obj.a();
-
ES6类的this
- 普通方法中,this指向被实例化的对象
- 静态方法中是当前类名也是构造函数,静态方法中无法获取到实例化对象的this
class Box{ static _instance; constructor(){ console.log(this);//指向被实例化的对象 } static getInstance(){ if(!Box._instance){ Box._instance=new Box(); } return Box._instance; } play(){ console.log(this,"|");//指向被实例化的对象 } static run(){ // console.log(this); console.log(this===Box,"____"); return this; } static plays(){ // this.getInstance().play(); var o=this.getInstance(); var o1=this.getInstance(); console.log(o===o1); } }
-
ES5面向对象中的this
- 类中的this指向window或undefined
- 面向对象方法中的this指向执行该方法的实例化对象
- 面向对象静态发方法中的this指向该类的类名
function Box(){ console.log(this); } Box.prototype.play=function(){ console.log(this);//this是指向执行该方法的实例化对象 } Box.run=function(){ console.log(this);//Box } // Box();//this是window或者undefined var b=new Box();// this是实例化后b对象 b.play();
-
箭头函数中的this
- this是箭头函数外this的指向
- 上下文环境
- 方法外的环境
- 上下文环境中this的指向
var obj = { a: function () { setTimeout(() => { console.log(this);//this是箭头函数外this的指向 // 上下文环境中this的指向 }, 2000); }, }; obj.a();
-
call apply bind
- this指向绑定的参数对象
- 如果使用call apply bind带入的参数是null,将会把this重新指向window
var obj={ a:function(){ function fn(){ console.log(this); } fn(); console.log(this);//window 如果是call apply bind 带入的是null,将会把这里的this重新指向window } } obj.a.call(null);
// Box();//this是window或者undefined
var b=new Box();// this是实例化后b对象
b.play();- 箭头函数中的this - this是箭头函数外this的指向 - 上下文环境 - 方法外的环境 - 上下文环境中this的指向 ```js var obj = { a: function () { setTimeout(() => { console.log(this);//this是箭头函数外this的指向 // 上下文环境中this的指向 }, 2000); }, }; obj.a();
-
call apply bind
- this指向绑定的参数对象
- 如果使用call apply bind带入的参数是null,将会把this重新指向window
var obj={ a:function(){ function fn(){ console.log(this); } fn(); console.log(this);//window 如果是call apply bind 带入的是null,将会把这里的this重新指向window } } obj.a.call(null);
-