普通函数和构造函数的区别
1、普通函数本质是与构造函数没有什么区别的。构造函数也是普通函数。创建方式两者一摸一样。在命名上构造函数的首字母一般要大写。
2、两者的调用方式不一样,普通函数直接调用,构造函数要使用new关键字来调用
3、new关键字作用:现创建了一个新的对象实例,将构造函数中的作用域指向这个新的对象。执行函数中的代码,将这个对象返回出去。
4、普通的函数一般没有返回值,为undefined。
5、普通函数,在调用时使用了new关键字,会正常执行,但是如果函数内部没有return,或者是return了一个基本数据类型,则返回一个空的对象。如果是构造函数中返回了一个基本数据类型,则会被创建的实例对象替换掉返回结果,如果返回了一个引用类型的数据,那么返回结果就是return的数据。
6、总的来说只要使用了new关键字,无论是不是构造函数,都会返回一个新的对象,区别就在于如果return了一个基本类型的数据,会被new创建的对象顶替掉,如果返回一个引用数据类型那么就会正常返回这个结果。
创建对象
创建对象一般有三种方式
1、字面量创建
var obj1 = {
uname: '张美丽',
age: 18,
sayHi: function() {
console.log('nihao');
}
};
2、使用new关键字和Object对象
var obj2 = new Object();
obj2.uname = '李红';
obj2['age'] = 19;
obj2.sayHi = function() {
console.log('你好');
};
这里的new如果没有写,效果是一样的,但是为了标准,都要加上。
3、使用构造函数的创建方式
function Person(uname, age) {
this.uname = uname;
this.age = age;
this.sayHi = function(arg) {
console.log('我说' + arg);
}
};
var p1 = new Person('张三', 18);
p1.sayHi('你真棒');
== 注意,使用构造函数创建的对象会在打印时前面带有构造函数的名字==
对象的遍历方法
对象的遍历方法有三种
1、使用for in遍历对象的属性
for (const key in obj) {
console.log(key);
}
这个方法会将对象中所有的属性遍历出来。包括其原型链上可以被枚举的属性。
2、使用Object.keys(),
var keys = Object.keys(obj);//返回一个由对象可枚举属性组成的数组
这个方法返回的是一个由可枚举的自身属性组成的数组。通过遍历这个数组就可以对对象进行遍历。
3、使用Object.getOwnPropertyNames()
Object.getOwnPropertyNames(obj).forEach(function (k,index) {
console.log(k);
console.log(index);
})
这个方法它会返回一个所有自身属性组成的数组,包括不可枚举属性。
检查对象的属性是否存在
有两种方法
1、使用 in 操作符
var obj1 = {
name: '杨家乐',
};
// 使用 in 操作符检查属性是否存在
console.log('name' in obj1); // true
console.log('age' in obj1); // false
2、使用obj.hasOwnproperty()方法检查是否具有属性
// 使用 hasOwnProperty() 方法检查属性是否存在
console.log(obj1.hasOwnProperty('name')); // true
console.log(obj1.hasOwnProperty('age')); // false
== 注意hasOwnProperty()只能在对象自身的范围中寻找属性,而in操作符不仅在自身寻找,而且还会在对象的原型上寻找。不够严谨。==
属性的分类
对象的属性分为数据属性与访问器属性。
1、 数据属性,属性里面保存着基本数据。它包含的是一个数据值的位置,在这可以对数据值进行读写。
var obj1 = {
firstName: '赵四',
lastName: '尼古拉斯',
}
保存着一些基本的数据类型。
2、访问器属性:这个属性不包含数据值,包含的是一对get和set的方法,在读写访问器属性时,就是通过这两个方法来进行操作进行的。
var obj1 = {
// 数据属性
uname: 'zhangsan',
age: 18,
// 访问器属性
// sexx: '男',
set gender(sex) {
this.sexx = sex;
},
get gender() {
return this.sexx;
}
};
当使用访问器属性访问和使用方法与正常写法一样,但是set方法里面必须有一个参数,不然会报错。当使用 . 来访问属性名时(gender)会调用get的方法,当给属性设置值时(用=赋值)会调用set的方法。
访问器属性的名字不能和对象已有属性进行重复,不然会造成栈溢出
数据特性,内部特性。
对象中的每一个属性都有自己的数据特性,这些特性决定了数据能否被修改,遍历,删除等。
1、configurable:这个表示属性能否被delete关键字进行删除,能否修改属性的特性,或者能够把属性修改为访问器属性。
2、enumerable:表示属性能否通过for-in循环遍历返回属性
3、writable:表示能否修改属性的值
4、value:表示该属性的数据值,默认是undefined。
以上属性中,布尔类型的默认值都是false,值类型的默认值都是undefined
获取查看对象的数据特性
使用Object.getOwnPropertyDescriptor()方法来获取对象的某条属性的数据特性。参数有两个,第一个是要获得的对象,第二个是要获得对象的属性。
var obj = {
// 数据属性
name:'张浩',
age:18,
// 访问器属性
get fullName(){
return this.name;
},
set fullName(name){
this.name = name;
}
}
console.log(Object.getOwnPropertyDescriptor(obj,'name'));
// configurable: true
// enumerable: true
// value: "张浩"
// writable: true
使用Object.getOwnPropertyDescriptors()获取对象的所有属性的数据特性。参数只有一个,就是想要获取的对象。
var obj = {
// 数据属性
name:'张浩',
age:18,
// 访问器属性
get fullName(){
return this.name;
},
set fullName(name){
this.name = name;
}
}
console.log(Object.getOwnPropertyDescriptors(obj));
age: {value: 18, writable: true, enumerable: true, configurable: true}
fullName: {enumerable: true, configurable: true, get: ƒ, set: ƒ}
name: {value: "张浩", writable: true, enumerable: true, configurable: true}
这些只是能够获取这些值,不能够修改,接下来使用一些方法来对对象属性的数据特性进行修改
**修改对象内部的数据特性 **
可以使用Object.defineProperty()对对象的某一个属性进行数据特性修改它所接受的参数有三个,第一个要修改的对象,第二个要进行修改的属性字符串形式,第三个是一个对象,里面写着要修改的内容
var obj = {
name:'张浩',
age: 18,
}
Object.defineProperty(obj,'name',{
configurable:true,
enumerable:false,
writable:true
});
console.log(obj);
这样一个一个修改效率肯定不行,我们可以使用Object.definePreperties()方法来一次性对对象的多个属性进行修改。
Object.defineProperties(obj, {
name: {
enumerable:false,
configurable:true,
writable:true
},
gender: {
enumerable:false,
configurable:true,
writable:true,
get: function () {
return this.name
},
set: function (e) {
this.name = e;
}
}
})
Object.definePreperties()不仅可以修改,还能创建一个新的对象,用法如下:给一个空的对象直接定义它内部特性。
var obj2 = Object.defineProperties({},{
name:{
value:'张浩',
},
fullNmae:{
get:function(){
return this.name;
},
set:function(newName){
this.name = newName;
}
}
})
console.log(obj2);
这样返回的对象中如果没有设置特性值,默认会为false和undefined。
禁止扩展
对象也有和属性一样类似的特性如[[Extensible]],它指明了对象本身是否可扩展的修改,默认情况下对象都是可以扩展的,随时都可以对象添加新的属性。如果设置了[[Extensible]]值为false,就能禁止对象添加新的属性。三种禁止扩展的方法。
1、Object.preventExtensions()将对象变成不可扩展的对象,这个方法接受一个参数,就是被修改的对象。对象被禁止扩展后就不能进行新属性的添加了。
name:'张浩',
age:18,
gender:'男'
};
// 1.禁止扩展(对象不能添加新的属性,但是可以删除,和修改,枚举。)
Object.preventExtensions(obj);
console.log(Object.isExtensible(obj));//true
console.log(obj);
2、Object.seal()封印对象,被封印的对象不能够被添加新的属性,不能删除,可以修改,可以枚举。
Object.seal(obj);
obj.sex = 1;//不能添加
delete obj.name;//不能删除
obj.name = '张三';//不能修改
console.log(obj);
console.log(Object.isSealed(obj));// true
console.log(Object.isExtensible(obj)); // false
3、Object.freeze()冻结对象,被冻结的对下个不能添加,修改,删除,可以枚举。就是说这个对象只能进行读取。
Object.freeze(obj);
obj.sex = 1;
delete obj.name;
obj.name = '张三';
console.log(obj);
console.log(Object.isFrozen(obj));// true
console.log(Object.isSealed(obj));// true
console.log(Object.isExtensible(obj));// false
这个三个其实是逐级递增的。isExtensible是判断是否是可扩展的,为true时就代表它是可以扩展的。