对象的创建方式
var obj = {}
叫做对象字面量或者叫做对象直接量
那么如何给当前对象添加一个属性和方法呢??
var obj = {};//对象字面量/对象直接量
obj.name = "huasheng";//添加属性
obj.sayName = function(){//添加方法,方法是个函数
console.log(this.name);
};
当前obj
中有一个name
属性和一个sayName
的方法,当obj
里面的sayName
方法一执行就把sayName
的名字打印出来
包装类(包装对象)
对象是有属性和方法的,只有对象有属性和方法而原始值是没有属性和方法的。
var str = "huasheng";
console.log(str.length);
console.log(str.indexOf("u"));
在JS中只有对象才能够属性和方法,这句话无安全是没有问题的,之所以我们能看到原始值有属性和方法是因为JS系统自动的给这些原始值添加了包装对象
new String()
var str = "huasheng";
console.log(str.length);
console.log(str.indexOf("u"));
字符串加上.
JS系统会给你加上new String(str)
这句话的,把你的str
里面的字符串给你传进去,把你的字符串"huasheng"
传进去包装成一个字符串对象,然后包装成一个字符串对象之后他就有属性了。
var str = "huasheng";
console.log(new String(str));
console.log(typeof new String(str));
他会把你str
属性传到new String
里面然后在包装成一个字符串对象,在使用里面的方法。
第一个是包装完的字符串对象,第二个用typeof
检查出来的结果他是一个object
表示一个对象
var str = "huasheng";
console.log(new String(str).length);
原始值他是不能使用方法和属性的,JS引擎只能把原始值包装成一个对象在使用,如现在查询str
里面的length
的长度,他是调用new String
的包装对象包装成一个字符串对象在使用。
new Number(num)
var num = 2;
console.log(num.toString());
那么num
是原始值,那为什么num
上面有一个to String()
函数呢,其实是JS引擎在你调用to String()
函数的时候给你包装成数字对象,调用new Number()
函数把num
给传进去变成一个数字对象在使用to String
方法
var num = 2;
console.log(new Number(num));
console.log(new Number(num).toString());
第一个是把num
当做参数传进去通过new Number()
函数包装成一个数字对象在使用,第二个是包装完的数字对象在调用to String
方法转换成字符串是"2"
var num = 2;
console.log( typeof new Number(num));
用typeof
一下检查出来的结果他是一个object
表示一个对象
new Boolean(bool)
var bool = false;
console.log(bool.toString());
那么bool
是原始值,那为什么bool
上面有一个to String()
函数呢,是JS引擎把这个bool
偷偷地包装成了一个布尔对象,通过new
函数启动了Boolean
函数把bool
传进去包装成一个布尔对象
var bool = false;
console.log(new Boolean(bool));
console.log(typeof new Boolean(bool));
第一个是把bool
当做参数传进去通过new
函数启动了Boolean
函数包装成一个布尔对象在使用,第二个是包装完的布尔对象用typeof
检查是一个object
类型表示一个对象
总结
在JS中只有对象才能够属性和方法
但是在JS中存在3个包装类
new Number(num)
--> 把原始值num
变成数字对象new Boolean(bool)
--> 把原始值bool
变成布尔对象new String(str)
--> 把原始值str
变成字符串对象
都是通过new
函数启动的Number
,Boolean
,String
函数的
在我们日常写JS代码中,根本不用包装成数字对象,包装成字符串对象,包装成布尔对象,这个只是解释为什么原始值可以有属性和方法。(只要知道JS中有包装类这个概念就可以了)
练习
var str = 'huasheng';
str = str + 3; //"huasheng"+3 --> "huasheng3"
var result = typeof str; //"string"
if (result.length === 6) {//length长度等于6走一下代码
result.len = '返回的结果是string';//new String(result)包装成一个字符串对象
//但是这个字符串对象在下一个是被销毁了根本没什么用
}
console.log(result.len); //undefined
console.log(result.length);//6
//result.length这个length属性是不能销毁的,length是一直存在字符串身上的。
src.length
这个length
属性是不能销毁的是默认存在的,length
是一直存在字符串身上的。
工厂模式&&构造函数
工厂模式
var person1 = {};
person1.name = 'huasheng';
person1.age = 28;
person1.sayName = function(){
console.log(this.name)
}
var person2 = {};
person2.name = '花生';
person2.age = 26;
person2.sayName = function(){
console.log(this.name)
}
var person3 = {};
person3.name = '牛肝菌';
person3.age = 25;
person3.sayName = function(){
console.log(this.name)
}
var person4 = {};
person4.name = '一念';
person4.age = 18;
person4.sayName = function(){
console.log(this.name)
}
用对象字面量的形式创建4个有相同属性的代码
在JS中会使用到许多的对象如上:
当前代码是有很多的,是有很多重复的,当我们要定义一些人,这些人都有相同的属性的时候,这会造成我们当前的代码重复量太多了
其实是可以吧这些重复的代码封装在一个函数中的
用函数的形式创建有相同属性的代码
function person(name,age){ //工厂模式
var obj = {}; //原料
obj.name = name; //加工
obj.age = age;
obj.sayName = function(){
console.log(this.name)
}
return obj; //出厂
}
var person1 = person('花生',28);
var person2 = person('huasheng',26);
var person3 = person('牛肝菌',25);
var person4 = person('一念',18);
function car(width,height,brand){ //工厂模式
var obj = {}; //原料
obj.width = width; //加工
obj.height = height;
obj.brand = brand;
return obj; //出厂
}
var car1 = car(250,200,'大众');
var car2 = car(220,180,'奔驰')
function phone(brand,color,price){ //工厂模式
var obj = {}; //原料
obj.brand = brand; //加工
obj.color = color;
obj.price = price;
return obj; //出厂
}
var phone1 = phone('iphone','黑色',5000);
var phone2 = phone('华为','白色',6000);
理由这种机制就可以简化我们的代码了。这种可以理解为是工厂模式
其实工厂模式他也是有弊端的,就在上面用工厂模式整的3块代码这样的代码重复量太累不好,那么怎么解决这种弊端呢
构造工厂模式(构造函数)
function Person(name, age) { //构造工厂模式
this.name = name;
this.age = age;
this.sayName = function () {
console.log(this.name)
}
}
var person1 = new Person("花生",28);
其实new
关键词是一种启动函数的方式,启动的时候会让函数内部发生变化
new
关键词的作用
- 生成一个空对象
{}
this
指向 生成的空对象{}
return
会默认的把this
抛出- 以上三点都是隐式的
通过new
关键词启动的函数,这个函数的名字必须首字母大写如Person
。
一旦在JS代码中看见一个单词的首字母大写的时候,那么这个单词就是构造函数(必须这样写JS代码的要求)
普通函数和构造函数没有任何的区别,都是可以通过new
函数启动。一旦一个函数通过new
关键词启动了那么这个函数就是构造函数。
function Person(name, age) { //构造工厂模式
this.name = name;
this.age = age;
this.sayName = function () {
console.log(this.name)
}
// return 2;//person1不会接受用return抛出的原始值
return [1,2,3];//person1会接受引用值抛出的结果
}
var person1 = new Person("花生",28);
但是如果人为的显式return
- 则原始值不会被抛出
- 引用值会被抛出
原型
创建一个构造函数
function Person(name,age){
this.name = name;//特性
this.age = age;//特性
this.sayName = function(){//共性
console.log(this.name);
}
}
var person1 = new Person("花生",28);
var person2 = new Person("huasheng",16);
在上面的代码中,name
名字和age
年龄是他们的特性也是(私有属性),sayName
是共性(是共同属性)。
那么他们的共同属性sayName
是不是他们的共同属性
console.log(person1.sayName === person2.sayName);
发现做全等比较的时候是false
不全等
说明了person1
和person2
的函数并不是一个函数,其实这是JS给person1
和person2
这两个函数分别开辟了两个空间的。
那么怎么把这两个函数的sayName
属性放在一个空间里呢??
function Person(name,age){//工厂
this.name = name;
this.age = age;
}
Person.prototype.sayName = function (){//原始的模子
console.log(this.name);
}
var person1 = new Person("花生",28);//出厂
var person2 = new Person("huasheng",16);
这会在给person1
函数中的sayName
属性和person2
函数中的sayName
属性作比较
console.log(person1.sayName === person2.sayName);
结果是true
,发现person1
函数中的sayName
属性和person2
函数中的sayName
属性并不是在person
函数中的。
Person.prototype
是原型(原始模型)是一个对象
那为什么person1
person2
中有sayName
方法并且是全等呢
那为什么person1
person2
中有sayName
方法
通过new
关键词启动了Person
函数然后生成了person1
和person2
,Person
函数他是一个工厂是可以生成函数的,而Person.prototype
是存储着原始的模型,person1
person2
都是通过这个原始模型往下做出来的,做出来的东西都保留着这个原始模型。
那为什么person1
person2
中有sayName
方法是因为原始的模型上有sayName
的方法,而person1
person2
都是这个原始模型做出来的东西自然而然就有保留sayName
这个方法了
那为什么person1
和person2
做比较时是全等呢??
是因为sayName
的从原始模型出来的而person1
和person2
是这个原始模型所出来的产品都保留这个原始的模型所以是true
通过new
关键词启动的函数时,生成一个空对象
其实这个对象不完全是空的他还是一个对象的。
他里面还是有东西的那就是{__proto__}
是JS内置的属性(可看可改)
只要是对象就有{__proto__}
这个属性是指一个属性的原始模型
他指向的是你用哪个函数启动的原始模型{__proto__:Person.prototype}
完整的Person
是如下
{
__proto__:Person.prototype,
name:'花生',
age:28
}
为什么person1.sayName
我们可以查到他是一个函数的呢??
当person1.sayName
他会往__proto__
这个属性里去找他指向的是Person.prototype
,而Person.prototype
他上面是有sayName
这个属性的。当一个函数里没有想要找的属性就去__proto__
里面去找,有就有没有则就没有
他们的连接点在于每个对象上面都有__proto__
这个属性是JS内置的属性他指向的是原始模型
对象查找属性的规则
- 先查找自身上面有没有指定属性
- 如果没有在自身上找到指定属性 ,那就从
__proto__
属性中查找有没有指定属性
练习题目
第一题
function Person(){
/*
* {
* __proto__:Person.prototype,
* }
* */
}
/*
* Person.prototype:{
* name:'oldsix'
* }
* */
Person.prototype.name = 'heaven';
var person1 = new Person();
Person.prototype.name = 'oldsix';
console.log(person1.name);
第二题
function Person(){
/*
* {
* __proto__:Person.prototype (1)
* }
* */
}
/*
* Person.prototype={ (1)
* name:'heaven'
* }
*
* Person.prototype={ (2)
* name:'oldsix'
* }
* */
Person.prototype.name = 'heaven';
var person1 = new Person();
Person.prototype = {
name:'oldsix'
}
console.log(person1.name);
第三题
function Person(){
/*
* {
* __proto__:Person.prototype(2)
* }
* */
}
/*
* Person.prototype={ (1)
* name:'heaven'
* }
*
* Person.prototype={ (2)
* name:'oldsix'
* }
*
* */
Person.prototype.name = 'heaven';
Person.prototype = {
name:'oldsix'
}
var person1 = new Person();
console.log(person1.name);