对象
概念理解
-
什么是对象,其实就是一种类型,即引用类型。而对象的值就是引用类型的实例。在ECMAScript中引用类型是一种数据结构,用于将数据和功能组织在一起,他常常被称为类。
-
万物皆对象,除了数字,字符,布尔这种绝对值以外的所有部分都是对象,
对象是类的实例化体现,类是对象的抽象体现。 -
每个对象都有自己的属性和方法
-
原型
- obj.proto
创建对象
-
new obj= new Object()
-
new obj = {}
- 字面量
-
new obj = Object.create()
- 函数构造法
new Object()
-
obj[属性]=属性值
-
obj[方法]=方法函数
-
var arr = new Object([])
- 创建数组,在javascript中数组不是单独的类型,它是由对象扩展出来的,因此,可以使用这种形式来建立数组。
- 一般不用这种方式创建数组和对象,会形成两层嵌套循环
原型链__proto__.__proto__⭐
-
与生俱来的方法和属性就是原型链上的方法和属性
-
实例化之后尝试的,属于后天形成的,不在原型链上
-
任何对象都是继承对象原型
-
万物皆对象
- 5种(string,number,boolean,undefined,null)基本类型实际也是对象,特殊处理存在栈中,但是调用需要去堆中找到该字符窜字符类型的方法并执行
-
-
解决重绘
- 1.同一时间集中起来重绘
- 2.预先处理数据,能不重绘的就不重绘
-
原型链的创建
- var o = {a:1}
- var o1 = Object.create(o);
- 以o作为原型链创建o1
-
属性
-
原型链上的属性
- 不允许直接改变原型链上的属性
-
获取
- 当设置对象的属性时,直接设置的是对象自身属性(对象属性);
- 如果获取时,首先查看该对象有没有这个名称的对象属性,如果有直接返回这个属性值
- 若果没有,直接继续向下查找紧邻的原型链中的属性是否具有该属性名,查找到距离该对象最近的原型链中的属性名后返回其值
-
解构
- o4={…o1,…o2,…o3}
- 将o1,o2,o3的所有属性解构产生新对象赋值给了o4
属性创建
-
Object.delete
- 删除对象的属性
- delete obj.a
-
Object.assign()
- 将一个或者多个对象中可枚举属性复制到第一个参数对象数中,
- 如果后面的对象属性与前面的对象属性相同时,则会覆盖前面的对象属性
- 原对象中增加复制的属性,引用地址不改变
- 继承属性和不可枚举的属性是不能被拷贝的
-
Object.defineProperty(对象,属性名,该属性的描述对象)
Object.defineProperty(obj, “a”, {
configurable: true,//该属性是否可以删除,并且该属性的描述对象是否可以更改
enumerable: true,//该属性是否可以枚举
writable: true,//该属性是否可写(不是只读)
value: 10,//该属性的值
});
详细定义对象的属性-
configurable: true,
- 该属性是否可以删除,并且该属性的描述对象是否可以更改
- 省略时默认值为false
-
enumerable: true,
-
该属性是否可以枚举
-
不可枚举的属性
-
不能复制
- var o=Object.assign({},obj);
- var o={…obj};
-
-
-
-
writable: true,
- 该属性是否可写(不是只读)
-
value: 10,
- 该属性的值
-
-
Object.defineProperties(obj, props)
给对象定义属性值
Object.defineProperties(对象,{
“属性名”:{
value:属性值,
writable:布尔值
}
})- 属性名必须是字符串,value后面的内容是属性的值,writable是该属性是否可写。
- ES6的类里面没有常量
-
Object.freeze(arr)
- 冻结对象,不能修改该对象的所有属性,不能删除所有属性
-
Object.getOwnPropertyNames(obj)
- 获取对象的所有对象属性名
- 获取对象下所有属性的名称,并返回一个数组,
- 该数组的内容就是这些属性名,该数组对元素是 obj 自身拥有的枚举或不可枚举属性名称字符串。
-
Object.getOwnPropertyDescriptor(obj,属性名)
- 获取对象属性的描述对象
-
Object.is(a,b)
-
类似于===
- 和===不同在于 NaN判断NaN是相同的
-
-
Object.isExtensible(obj)
- 不可以增加新属性
- 是否是可扩展
-
Object.isFrozen(obj)
- 判断对象是否冻结
-
obj.hasOwnProperty(“e”)⭐
- in也可以判断属性的有无
- 对象原型链上的属性不是它的属性
- 当前对象的对象属性,原型链属性不属于范围
-
o.isPrototypeOf(o2)⭐
Box.isPrototypeOf(Ball)
//Ball的父类是否有Box类
Box.isPrototypeOf(b.constructor)
//b对象的父类中有没有Box类
HTMLElement.isPrototypeOf(div.constructor)
//是不是HTML标签- o是不是在o2的原型链上
- o2的父类中有没有o
-
obj.propertyIsEnumerable(“b”)
- 查询属性是否是不可枚举属性
-
b instanceof Box⭐
-
b是不是box类别
-
等价于b.constructor===Box
-
判断是否为空
- b instanceof Object
- 结果为false
-
b.constructor===Object 报错
-
继承不能
-
-
空和undefined区别
- index in arr
- arr.hasOwnProperty(index)
- 空对象不存在constructor
深复制⭐⭐⭐
- 题
var obj={
a:1,
b:2,
c:[1,2,3],
z:document.createElement("div"),
d:{
e:new Date(),
f:/a/g,
g:function(s){
console.log(s);
},
h:{
}
}
}
Object.defineProperties(obj.d.h,{
i:{
value:10
},
j:{
configurable:true,
value:[1,2,3,4]
},
k:{
writable:true,
value:{
l:{},
m:"abcde",
n:true,
o:[1,2,3]
}
}
})
Object.defineProperties(obj.d.h.k.l,{
p:{
value:function(){
console.log("p")
}
},
q:{
value:{
r:{a:1},
j:{b:2}
}
}
});
- 代码
function cloneObj(source,target){
if(target==undefined) target={};
var names=Object.getOwnPropertyNames(source);
for(var i=0;i<names.length;i++){
var desc=Object.getOwnPropertyDescriptor(source,names[i]);
if(typeof desc.value==="object" && desc.value!==null){
var obj;
switch(true){
case desc.value.constructor===Date:
obj=new Date(desc.value.toString());
break;
case desc.value.constructor===RegExp:
obj=new RegExp(desc.value.source,desc.value.flags);
break;
case HTMLElement.isPrototypeOf(desc.value.constructor):
obj=document.createElement(desc.value.nodeName);
break;
default:
obj=new desc.value.constructor()
}
Object.defineProperty(target,names[i],{
enumerable:desc.enumerable,
writable:desc.writable,
configurable:desc.configurable,
value:obj
});
cloneObj(desc.value,obj);
}else{
Object.defineProperty(target,names[i],desc)
}
}
return target;
}
函数执行
fn()
- this =>window
自执行函数
apply()
- fn.apply(obj)
- apply只有两个参数,第一个参数是this指向的对象,第二个参数是函数所需的所有参数的数组,列表
call()
- fn.call(obj)
- 第一个参数是函数中this指向的对象,后面会按顺序带入参数
bind()
红黄绿灯
var id;
function setLight() {
arguments[0](arguments[1], arguments[2]);
}
function showLight(fn,fn2){
clearTimeout(id);
console.log(this.toString());
id = setTimeout(fn, 2000, fn2, arguments.callee.bind(this));
}
setLight(showLight.bind("红"),showLight.bind("黄"),showLight.bind("绿"));
- 改变this指向,并封装起来,等待执行
- 通过bind可以对于回调函数传参,this就是bind绑定的内容
this指向⭐⭐⭐
严格模式 “use strict”;
- ES5严格模式,ES6,全局中this仍然指向window,函数中this指向undefined
非严格模式
- ES5非严格模式 全局中this和函数中this都指向window
对象中的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就指向对象外this的指向
回调函数
var obj = {
a: function () {
console.log(this,"____");
var self=this;
function fn1(fn) {
fn();
arguments[0]();
fn.call(self);
}
function fn2() {
console.log(this);//window 回调函数中
1、如果直接指向的回调函数,this指向最外层window
2、如果通过arguments直接使用参数指向函数,this则指向执行当前函数的arguments
3、如果回调函数通过call,apply,bind重新指向了新的对象时,this就是指向新对象
}
fn1(fn2);
},
};
obj.a(); */
- 1、如果直接指向的回调函数,this指向最外层window
- 2、如果通过arguments直接使用参数指向函数,this则指向执行当前函数的arguments
- 3、如果回调函数通过call,apply,bind重新指向了新的对象时,this就是指向新对象
事件中this
var obj={
b:1,
a:function(){
// 特殊的回调函数
document.addEventListener("click",this.clickHandler);
},
clickHandler:function(e){
console.log(this);//事件侦听的对象 e.currentTarget
}
this指向document
- IE 8 attachEvent侦听事件时,this指向window
ES6类
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,"____");
// this就是当前类名也是构造函数
// 任何的静态方法中this都是当前类
// 静态方法中无法获取到实例化对象的this的
return this;
}
static plays(){
// this.getInstance().play();
var o=this.getInstance();
var o1=this.getInstance();
console.log(o===o1);
}
}
// var b=new Box();//会执行构造函数,这是构造函数中this就是这个b对象
// b.play();//b对象下的方法play,因此play方法中this被指向b,谁执行play,this指向谁
// console.log(Box.run()===b);//false
// console.log(Box.run()===b.constructor);//true
-
constructor()中的this指向被实例化的对象
-
静态方法中
- 任何的静态方法中this都是当前类
- 静态方法中无法获取到实例化对象的this的
- this就是当前类名也是构造函数
ES5 面向对象中的this
- constructor()中的this指向被实例化的对象
箭头函数
var obj = {
a: function () {
setTimeout(() => {
console.log(this);//this是箭头函数外this的指向
// 上下文环境中this的指向
}, 2000);
},
};
obj.a();
- this是箭头函数外this的指向
- 上下文环境中this的指向
call apply bind
- this指向obj
- 数组隐式类型转换为字符串,会在每个元素间添加一个逗号