之前曾简单的介绍过对象,本文将对对象进行更深入的总结,可搭配之前的基础部分一起食用
var naruto = {
name : 'Naruto',
'first name' : 'Uzumaki',
age : '16',
chakela : 100,
yingfenshen : function() {
console.log('影分身之术');
this.chakela --;
},
xianrenmoshi : function() {
console.log('仙人模式');
this.chakela ++;
}
}
将《火影忍者》中的鸣人抽象为对象,有姓名(name)、姓氏(first name)、年龄(age)、查克拉(chakela)这四个属性,有影分身,仙人模式两个方法,分别会消耗会增长查克拉。
1.增、删、改、查
1.1 查
访问对象的属性和方法的方式通常有两种
1.1.1 点方法
console.log(naruto.name);//Naruto
对象名 . 属性名(方法名)可读取对象的属性和方法
1.1.2 方括号表示法
console.log(naruto['name']);//Naruto
使用方括号表示法,应将要访问的属性名以字符串的形式放在方括号中。
如果属性名中包含会导致语法错误的字符,或者属性名使用的是关键字或保留字,则推荐使用方括号表示法。
console.log(naruto.'first name');//error
console.log(naruto['first name']);//Uzumaki
1.2 增
增加属性或方法:
- 对象名 . 新增的属性名或方法名 = 属性值或函数
- 对象名[‘新增的属性名或方法名’] = 属性值或函数
naruto.luoxuanwan = function() {
console.log('螺旋丸');
}
naruto['son'] = 'Boruto';
1.3 删
删除属性或方法:
- delete 对象名 . 属性名或方法名
- delete 对象名[‘属性名或方法名’]
delete naruto.son;
console.log(nartuo.son);//undefined
delete naruto['xianrenmoshi'];
console.log(nartuo.xianrenmoshi);//undefined
访问对象的一个不存在的属性或方法并不会直接报错,而是undefined
1.4 改
修改属性或方法与新增大致相同:
- 对象名 . 待修改的属性名或方法名 = 新的属性值或函数
- 对象名[‘待修改的属性名或方法名’] = 新的属性值或函数
naruto.age = 27;
2.对象的创建方法
2.1 对象字面量
形式:
var obj = { }
2.2 构造函数
2.2.1 系统自带构造函数 Object()
使用new加上构造函数的执行,执行会返回一个对象,创建一个变量来接收返回结果
var obj = new Object();
obj.name = 'abc';
obj.say = function (){
}
2.2.2 自定义构造函数
构造函数遵循大驼峰命名规则(首字母大写)
theFirstName(小驼峰)
TheFirstName(大驼峰)
将构造函数创建对象的过程想象成工厂生产产品的过程,构造函数规定了产品的基本规格,而对象就是创造出来的产品。假设我们是一个汽车生产工厂
function Car() {
this.brand = 'BMW';
this.height = '1400';
this.lang = '4900';
this.kilometres = 0;
this.run = function () {
this.kilometres ++;
}
}
var car = new Car();//Car {brand: "BMW", height: "1400", lang: "4900", kilometres: 0, run: ƒ}
var car1 = new Car();//Car {brand: "BMW", height: "1400", lang: "4900", kilometres: 0, run: ƒ}
构造函数Car()规定了汽车的基本规格,生产的car与car1有着相同的规格,但却是相互独立的两辆车,并不会互相影响。第一辆车的公里数与第二辆无关
car.run();
console.log(car);//Car {brand: "BMW", height: "1400", lang: "4900", kilometres: 1, run: ƒ}
console.log(car1);//Car {brand: "BMW", height: "1400", lang: "4900", kilometres: 0, run: ƒ}
除了基本规格,我们工厂还提供选配服务(通过参数)
function Car(color) {
this.color = color;
this.brand = 'BMW';
this.height = '1400';
this.lang = '4900';
this.kilometres = 0;
this.run = function () {
this.kilometres ++;
}
}
var car = new Car('red');
var car1 = new Car('white');
举个小例子,模拟卡卡西班
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.teacher = 'Kakashi';
}
var naruto = new Person('Naruto', 16, 'male');//Person {name: "Naruto", age: 16, sex: "male", teacher: "Kakashi"}
var sasuke = new Person('Sasuke', 16, 'male');//Person {name: "Sasuke", age: 16, sex: "male", teacher: "Kakashi"}
var sakura = new Person('Sakura', 16, 'female');//Person {name: "Sakura", age: 16, sex: "female", teacher: "Kakashi"}
3. 构造函数内部原理
构造函数三段式
前提:函数执行语句前加上关键字new
- 创建一个this空对象在AO中
- 执行this.xxx = xxx;
- 隐式返回构造好的this
function Person(name, age, sex) {
//1.创建一个this空对象var this = {};
//2.执行this.xxx = xxx;
this.name = name;
this.age = age;
this.sex = sex;
this.teacher = 'Kakashi';
//3.隐式返回构造好的this return this;
}
var naruto = new Person('Naruto', 16, 'male');
var sasuke = new Person('Sasuke', 16, 'male');
var sakura = new Person('Sakura', 16, 'female');
于是我们可以模拟构造函数(只为加深印象,实际中不会这么使用)
function Person(name, age, sex) {
var that = {};
that.name = name;
that.age = age;
that.sex = sex;
return that;
}
var naruto = Person('Naruto', 16, 'male');
如果我们显式的返回一个对象值,则会破坏三段式
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.teacher = 'Kakashi';
return {};
}
var naruto = new Person('Naruto', 16, 'male');
console.log(naruto);//{}
可显式的返回原始值,则不会被破坏
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.teacher = 'Kakashi';
return 123;
}
var naruto = new Person('Naruto', 16, 'male');
console.log(naruto);//Person {name: "Naruto", age: 16, sex: "male", teacher: "Kakashi"}
4. 包装类
4.1 原始值与对象
若需给数字添加属性和方法,则可使用包装类创建数字型对象(字符串,布尔值同理)
var num = new Number(123);
var str = new String('abc');
var bol = new Boolean('true')
数值会存放在对象中的[[PrimitiveValue]]属性中
[[PrimitiveValue]]: 123
数字型对象可以有自己的属性与方法
num.abc = 456;
num.sayNum = function () {
console.log(this.abc);
}
num.sayNum();//456
数字型对象参与运算则会从对象变为原始值
console.log(num * 2)//246;
4.2 看个例子
var str = 'abcd';
str.a = 'a';//不报错
console.log(str.a);//undefined
console.log(str.length);//4
创建一个字符串str,按照经验,原始值不可能有属性和方法。可给str变量添加属性的操作并不报错,输出该属性的值为undefined,且可调用str.length方法。造成这种现象的罪魁祸首就是包装类。
4.3 包装类
在原始值查找或调用属性或方法时,因为自身不能拥有,所以会隐式的创建一个原始值类型的对象,给对象添加一个属性或方法,然后删除。再次访问时,又会重新隐式的创建一个新的对象,所以访问结果为undefined。由于String构造函数中本就有length属性,在访问str的length属性时,会隐式的创建一个参数为’abcd’的String()对象,再访问其length属性,所以输出结果为4,这些隐式创建对象的过程就是包装类。
var str = 'abcd';
str.a = 'a';
//new String('abcd').a = 'a'; delete
//
//new String('abcd').a;
console.log(str.a);//undefined
//new String('abcd').length;
console.log(str.length);//4
思考
var str = 'abcd';
str.length = 2;
console.log(str);
console.log(str.length);
var arr = [1, 2, 3, 4];
arr.length = 2;
console.log(arr);
原始值并不能有属性和方法,系统会隐式创建对象,对对象的属性进行操作后销毁。接着访问str,因为属性已被删除,所以输出结果不会受任何影响
var str = 'abcd';
str.length = 2;
//new String('abcd').length = 2; delete
console.log(str);//'abcd'
而对数组而言,数组本身就具有length属性。修改length属性的长短,则会截断数组
var arr = [1, 2, 3, 4];
arr.length = 2;
console.log(arr);//[1, 2]
面试题
var str = 'abc';
str += 1;
var test = typeof(str);
if(test.length === 6) {
test.sign = 'typeof的返回值可能为Strig';
}
console.log(test.sign);
实际过程
var str = 'abc';
str += 1; //'abc1'
var test = typeof(str);//test === 'string'
if(test.length === 6) {
test.sign = 'typeof的返回值可能为Strig';
//new String(test).sign = 'typeof的返回值可能为Strig';
//delete
}
//new String(test).sign
console.log(test.sign);//undefined