面向对象编程(三)

389 阅读6分钟

Object对象中相关方法的介绍

Object对象本身的方法

Object的静态方法

Object.keys()

获取,参数是一个对象,返回是一个数组。Object.keys()只能获取可枚举的属性名,此方法常用。

var arr = ['a','b','c'];
Object.keys(arr);//['0','1','2']
var obj = {
    name: 'john',
    age:18
};
Object.keys(obj);//['name','age']

Object.hasOwnPropertyNames()

获取属性名,接收一个对象作为参数,返回一个数组,包含了该对象自身所有的属性名。Object.hasOwnPropertyNames()返回不可枚举和枚举的属性名,可以获取继承和不可遍历的属性

var arr = ['a','b','c'];
Object.hasOwnPropertyNames(arr);//['0','1','2','length']
var obj = {
    name: 'john',
    age:18
};
Object.keys(obj);//['name','age']

Object.getPrototypeOf()

参数是该对象,返回该对象的原型,也是获取原型对象的标准方法

function Fn(){};
var f1 = new Fn();
Object.getPrototypeOf(f1)===Fn.prototype;//true
//特殊对象的原型
//1.空对象的原型是Object.prototype
Object.getPrototypeOf({})===Object.prototype;//true
//2.Object.prototype的原型是null
Object.getPrototypeOf(Object.prototype)===null;//true
//3.函数的原型是Function.prototype
function f(){};
Object.getPrototypeOf(f)===Function.prototype;//true

Object.setPrototypeOf()

接收两个参数,第一个参数是现有对象,第二个是是原型对象

var a = {};
var b = {x:1};
Object.setPrototypeOf(a,b);
console.log(a.x);//1
//模拟new关键字
function Fn(){
    this.foo = 'foo';
}
//var f = new Fn();
var f = Object.setPrototypeOf({},Fn.prototype);
Fn.call(f);

Object.create()

一个实例对象生成另一个实例对象,接收一个对象作为参数,然后以他为原型,返回一个实例对象

var A = {
    hello:function(){
	console.log('hello');
    }
};
var B = Object.create(A);
Object.getPrototypeOf(B);
B.hello();

Object的实例方法

Object.prototype.valueOf()

返回当前对象的值,默认情况下返回对象本身

var obj = new Object();
obj.valueOf()===obj//true

//用自定义的Object.valueOf 覆盖 Object.prototype.valueOf()
obj.valueOf = function(){
	return 2;
}
//console.log(1+obj);//1[object Object]
console.log(1+obj);//3

Object.prototype.toString()

返回一个对象的字符串形式,默认返回类型的字符串

var obj2 = {a:1};
//用自定义的Object.toString() 覆盖 Object.prototype.toString()
obj2.toString = function(){
    return 'hello'
}
//obj2.toString();//[object Object]
obj2.toString();//hello

Object.prototype.toLocaleString()

依赖地区,不常用。

Object.prototype.isPrototypeOf()

用来判断该对象是否是另一个对象的原型

var o1 = {};
var o2 = Object.create(o1);
var o3 = Object.create(o2);
o2.isisPrototypeOf(o3);//true
o1.isisPrototypeOf(o3);//true

Object.prototype.isPrototypeOf({});//true
Object.prototype.isPrototypeOf([]);//true
Object.prototype.isPrototypeOf(Object.create(null));//false

Object.prototype.hasOwnProperty()

接收一个字符串作为参数,返回一个布尔值,表示该实例对象自身是否具有该属性,与继承来的属性没有关系,继承来的属性返回false

var obj = {
    a:123
}
obj.hasOwnProperty('a');//true

Object.prototype.propertyIsEnumerable()

判断属性是否有枚举性(可遍历),只能判断实例本身的属性,对于继承来的属性和设置不可枚举的属性一律返回false

var obj = {};
obj.a = 123;
for (var key in obj){
    console.log(key);
}
obj.propertyIsEnumerable(a);//true

属性描述对象

一个对象内部的数据结构

var obj = {};
obj.name= 'john';
obj.name = 'huahua';
console.log(delete obj.name);
console.log(obj.name);

/*
{
value:huahua,
writable:true,
enumerable:true,
configurable:true,
set:undefined,
get:undefined
}*/
//获取属性描述对象
console.log(Object.getOwnPropertyDescriptor(obj,'name'));

Object.getOwnPropertyDescriptor()

可以获取属性描述对象,第一个参数是目标对象,第二个参数是一个字符串(目标对象的属性名)。不能用于继承的属性,只能用于对象自身的属性

var obj = {};
obj.name= 'john';
obj.name = 'huahua';
console.log(delete obj.name);
console.log(obj.name);

//获取属性描述对象
console.log(Object.getOwnPropertyDescriptor(obj,'name'));/*{
value:huahua,
writable:true,
enumerable:true,
configurable:true,
}*/

Object.defineProperty()

定制单个属性

//Object.defineProperty(属性所在的对象,属性名,属性描述对象)
var obj= Object.defineProperty({},'name',{
    value:'john',
    writable:false,//可写性
    enumerable:true,//可遍历性
    configurable:false//是否可配置
});
console.log(obj.name);//john
obj.name = 'huahua';
console.log(obj.name);//john,不可写
for (var key in obj){
    console.log(obj[key]);//john,可遍历
}
delete obj.name;
console.log(obj.name);//john,不可配置

Object.defineProperties()

定制多个属性

var obj = Object.defineProperties({},{
    p1:{
        value:123,
    	enumerable:true,//可遍历性
    },
    p2:{
        value:'john',
    	enumerable:false,
    },
    p3:{
        get:function(){
            return this.p1+this.p2
        },
        enumerable:true,
        configurable:true//可配置
    }
})
console.log(obj);

注意:

  • 一旦定义了取值函数get,就不能同时定义value,否则会报错。
  • 一旦定义了取值函数get,就不能同时定义writable,否则会报错。

属性描述对象中的相关属性

value
var obj = {};
obj.a = 123;
Obj.getOwnPropertyDescriptor(obj,'a').value;

Object.defineProperty(obj,'p',{
    value:456,
});
console.log(obj.p);//456
writable
var obj = {};
obj.a = 123;
Object.defineProperty(obj,'p',{
    value:789,
    writable:false
});
console.log(obj.p);//789
obj.p=890;
console.log(obj.p);//789;

var pro = Object.defineProperty({},'foo',{
    value:'a',
    writable:false
});
var obj2 = Object.create(pro);
//console.log(obj2.foo);
//obj2.foo = 'b';
//console.log(obj2.foo);//a
Object.defineProperty(obj2.'foo',{
    value: 'b',                
});
console.log(obj2.foo);
enumerable

可遍历性

如果一旦enumerable设置了false,通常以下三个操作不会取到该属性

  • for...in
  • Object.keys()
  • JSON.stringify()
var obj = {};
Object.defineProperty(obj,'foo',{
    value:123,
    enumerable:false
});
console.log(obj.foo);
for (var key in obj){
    console.log(obj[key])
}

console.log(Object.keys(obj));//[]

console.log(JSON.stringify(obj));//{}

注意

for...in循环可以遍历继承来的属性

function B(){
    this.name = 'john'
}
function A(){
    B.call(this)
}
var c = new A();
console.log(c.name);//john
for (var key in c){
    console.log(c[key]);//john
}
//Object.keys()可以获取继承来的属性
Object.keys(c);//['name']
configurable

是否可配置,决定是否可以修改属性描述对象。

注意

  • 一旦设置configurablefalse,属性描述对象value,writable,enumerable,configurable都不能被修改,也不能删除属性。
  • writable只有在false改为true的时候会静态失败,true改为false会允许
  • 只要writableconfigurable有一个为true,就允许被修改
var obj = {};
Object.defineProperty(obj,'a',{
    value:4,
    writable:false,
    enumerable:false,
    configruable:false
});
console.log(obj);
obj.a = 3;
console.log(obj.a);

存取器
var obj = Object.defineProperty({},'p',{
	get:function(){
        return 'getter'
    },
    set:function(value){
        console.log('setter:'+value)
    }
});
obj.p;//getter
obj.p = 123;

//简便写法
var obj = {
    get p(){
    	 return "getter"; 
    },
    set p(value){
	console.log('setter:'+value);
    }
}
console.log(obj.p);
obj.p = 123;

浅拷贝

//基本数据类型:按值传递
var a = 1;
var b = a;
b = 100;
console.log(b);//100
console.log(a);//1
//引用数据类型:按引用地址传递
var arr = [1,2,3];
var newArr = arr;
newArr.push(4);
console.log(newArr);//[1,2,3,4]
console.log(arr);//[1,2,3,4]

拷贝:浅拷贝和深拷贝

操作拷贝之后的对象的某个属性不会影响原始对象中的属性,这种拷贝就称为深拷贝,反之,有影响叫浅拷贝。

var obj = {
    name:'john',
    age:20,
    hobby:'eat',
    gildfriend:{
        name:'huahua',
        age:18,
        hobby:'eat'
    }
};
function shadowCopy(toObj,fromObj){
    //实现浅拷贝
    for (var key in fromObj){
	toObj[key] = fromObj[key];
    }
	return toObj;
}
var newObj = shadowCopy({},obj);
newObj.age = 30;
newObj.girldfriend.hobby = 'sleep';

浅拷贝不是直接赋值,浅拷贝新建了一个对象,将原来对象的属性都一一复制过来,复制的是值,而不是引用。浅拷贝只是复制了第一层的属性,并没有递归所有的值复制过来

深拷贝

对目标对象的完全拷贝,不像浅拷贝只是复制了一层的引用,就连值也复制过来。只要进行了深拷贝,他们是老死不相往来,谁也不影响谁。

var obj = {
    name:'john',
    age:20,
    hobby:['eat','song'],
    gildfriend:{
        name:'huahua',
        age:18,
        hobby:'eat',
        friend:{
        name:'xinxin',
        age:23,
        hobby:'money'
    	}
    }
};
function deepCopy(to,from){
    //遍历from对象的所有的的属性,copy到to对象中
    for (var key in from){
        //不遍历原型链上的属性
        if(from.hasOwnProperty(key)){
            //如果值是对象并且有值,继续遍历
            if(from[key]||typeof from[key]==='object'){
                //区分是一般对象还是数组
              	to[key] =  from[key].constructor === Array?[]:{};
                console.log(to[key]);
                to[key] = deepCopy(to[key],from[key]);
               }
            //如果不是,直接赋值
            else{
		to[key] = from[key];
            }
        }
    }
    return to;
}
var newObj = deepCopy({},obj);
console.log(newObj);
newObj.friend.name = '小红';
console.log(newObj);

模块的基本实现

简单的说一个js文件就是一个模块

<script src="module.js"></script>
<script>
    module.m1();//m1
    module.m2();//m2
</script>
var module = (function(){
    var count = 0;
    var m1 = function(){
        console.log('m1');
        //...
    };
    var m2 = function(){
        console.log('m2');
        //...
    };
    return{
        m1:m1,
        m2:m2
    }
})();

放大模式

<script src="module.js"></script>
<script>
    module.m1();//m1
    module.m2();//m2
    console.log(module);
</script>
var module = (function(){
    var count = 0;
    var m1 = function(){
        console.log('m1');
        //...
    };
    var m2 = function(){
        console.log('m2');
        //...
    };
    return{
        m1:m1,
        m2:m2
    }
})();
(function(mod){
    module.m3 = function(){
        console.log('m3')
    }
    return mod;
})(module);

宽放大模式

最终写法

...
(function(mod){
    module.m3 = function(){
        console.log('m3')
    }
    return mod;
})(window.module||{});

命名空间

作用

全局作用域下,避免变量的污染

<script src='namespace.js'></script>
<script src='namespace_sub.js'></script>
<script>
    console.log(namespace);
    var p1 = new namespace.PersonInfo({name:'john',gender:'男'});
    console.log(p1);
    namespace.personInfoUtil.show(p1);
    var helloStr  = p1.getHello();
    console.log(helloStr);
    var c = new namespace.sub.Cat('huahua','白色');
    c.sleep();
</script>
//个人信息类
//姓名 性别
var namespace = function(namespace){
    //声明了一个顶层的命名空间
    //个人信息类:构造函数构建对象
    namespace.PersonInfo = function(obj){
        obj = obj||{};
        this.name = obj.name||"";
        this.gender = obj.gender||"?";
    }
    namespace.PersonInfo.prototype.getApplication = function(){
        var str = '';
        if(this.gender === '男'){
            str = '男士';
        }else{
            str = '女士'; 
        }
        return str;
    }
    namespace.PersonInfo.prototype.getHello = function(){
        var s = 'hello'+this.name+this.getApplication();
        return s;
    }
    //个人信息工具类
    namespace.personInfoUtil = function(){
        return {
            //p形参是代指哪个对象
            show:function(){
                alert('姓名:'+p.name,'性别:'+p.gender)
            }
        }
    }();
    return namespace;
})(window.namespace||{});
//动物园
namespace.sub = (function(sub){
    //定义了一个子命名空间
    //动物类
    sub.Animal = function(name,color){
        this.name = name;
        this.color = color;
    };
    sub.Animal.prototype.sleep = function(){
        console.log('睡懒觉')
    }
    //猫类
    sub.Cat = function(name,color){
        //继承属性
        sub.Animal.call(this,name,color);
    }
    //继承方法
    sub.Cat.prototype = Object.create(sub.Animal.prototype);
    sub.Cat.prototype.constructor = sub.Animal;
    return sub;
})(window.namespace.sub||{});