JavaScript 对象
对象
用已学的知识点,描述一下你心目中的对象。
属性的增、删、改、查
对象的创建方法
1. 字面量
2. 构造函数
系统自带 new Object(); Array(); Number(); Boolean(); String(); Date();
自定义
3. Object.create(原型)方法
对象是一种基础的变量类型,对象和数组、function都属于引用值,引用值的赋值形式是和原始值不同的
一、描述一下心目中的对象
生活中任何一个东西都可以抽象成一个对象,对象里面可以有属性、有方法。方法致力改变对象的属性,或者说互相更改也可以。
比如把桌子看成一个对象,桌子有它的属性和方法
1. 桌子的属性,有四个腿、长宽高、颜色
2. 桌子的方法,可以承载一些东西、可以受重、可以登高
把灯管看成一个对象的话,灯管可以集中为一些属性和方法的集合
1. 比如灯长、宽、半径、周长都是灯的属性,
2. 可以发亮是灯管的一个方法,有一个方法控制开关,开了就发亮关了就灭。
人也是一样,
可以把很多共有的一些有联系的属性抽象成一个对象,可以当做人一样去表达,或者反着说,拿一个人当做对象,这个对象有什么样的属性和方法
对象mrDeng的属性
1. name属性
2. age属性
3. sex属性
4. health属性是一个健康值
5. smoke属性值是方法(一个函数),我们管这样的属性值叫方法或者叫函数也可以,对象上面叫方法正常叫函数
6. drink属性值是方法
var mrDeng = { name: "MrDeng", age: 40, sex: "male", health: 100, smoke: function(){ console.log("I am smoking ! cool!!!"); }, drink: function(){ console.log("I am drink"); } } console.log(mrDeng.health); // health属性是一个健康值(返回100),在外部改变headlth属性的值 mrDeng.health ++; // 改变health属性的值,值变成101 console.log(mrDeng.health); // 101
调用 mrDeng.smoke() 方法修改health属性值
1. mrDeng.smoke 代表这个smoke函数体的引用,只不过把函数体的引用挂到对象属性上了所以叫方法
2. mrDeng.smoke() 把函数引用拿出来能正常执行,smoke方法里面有 health--
3. mrDeng.drink() drink方法里面 health++
var mrDeng = { name: "MrDeng", age: 40, sex: "male", health: 100, smoke: function(){ console.log("I am smoking ! cool!!!"); mrDeng.health --; }, drink: function(){ console.log("I am drink"); mrDeng.health ++; } } console.log(mrDeng.smoke); // ƒ (){ console.log("I am smoking ! cool!!!"); mrDeng.smoke --; } mrDeng.smoke(); // I am smoking ! cool!!! console.log(mrDeng.health); // 99 mrDeng.drink(); // I am drink console.log(mrDeng.health); // 100 mrDeng.drink(); // I am drink mrDeng.drink(); // I am drink console.log(mrDeng.health); // 102
PS:
在控制台调用函数,函数没有设置返回值默认返回undefined,有return返回值就打印返回值
一个新的小知识:
麦克阿瑟(网红,玉米烟斗,炒作自己)缺心眼,自己说:伟大的麦克阿瑟说过……,麦克阿瑟今天很高兴……
一般介绍自己说话用第一人称我,没有称呼自己名字的,对象里面也有一个第一人称叫 this ,this有很多其它用法,现在记住this是第一人称就可以了
var mrDeng = { name: "MrDeng", age: 40, sex: "male", health: 100, smoke: function(){ console.log("I am smoking ! cool!!!"); this.health --; // this指的是mrDdeng }, drink: function(){ console.log("I am drink"); this.health ++; } } mrDeng.smoke(); // I am smoking ! cool!!! console.log(mrDeng.health); // 99
自己练习
在方法里打印this,和直接打印this,看看各指向哪里
var mrDeng = { name: "MrDeng", age: 40, sex: "male", health: 100, smoke: function(){ console.log("I am smoking ! cool!!!"); this.health --; }, drink: function(){ console.log("I am drink"); this.health ++; }, myFun: function(){ console.log(this); // 方法里打印this的是mrDeng对象,因为是该对象调用的myFun方法 }, myAttribute: this, // 打印的是window } mrDeng.myFun(); // {name: 'MrDeng', age: 40, sex: 'male', health: 100, smoke: ƒ, …} console.log(mrDeng.myAttribute); // Window {window: Window, self: Window, document: document, name: '', location: Location, …}
二、属性的增删改查
学习任何一个东西都要符合一个原则
1. 先看操作,怎么样操作
2. 再看是怎么构成的
任何一个东西的操作离不开四步增、删、改、查,
这四个词是数据库里面的专业用词,其实这不是给数据库创造的四个词,是给操作创造的四个词,计算机里通用的操作就是增删改查
1、属性的增加
给MrDeng对象增加属性 mrDeng.wife = "XiaoLiu" ,增加新属性名wife,属性值 "XiaoLiu" 必须写,不写值就成访问属性了
var mrDeng = { name: "MrDeng", age: 40, sex: "male", health: 100, smoke: function(){ console.log("I am smoking ! cool!!!"); this.health --; }, drink: function(){ console.log("I am drink"); this.health ++; } } mrDeng.wife = "XiaoLiu"; console.log(mrDeng); // 打印mrDeng对象
打印mrDeng对象,对象里面有 wife:"XiaoLiu" 这个属性了
2、查看属性
查看属性很简单
var mrDeng = { name: "MrDeng", age: 40, sex: "male", health: 100, smoke: function(){ console.log("I am smoking ! cool!!!"); this.health --; }, drink: function(){ console.log("I am drink"); this.health ++; } } console.log(mrDeng.sex); // male console.log(mrDeng); // 控制台输出的是mrDeng对象 {name: "LiLi", age: 37, sex: "female", health: 100, work: ƒ, …} document.write(mrDeng); // 输出的是[object Object]
有些信息必须输出到控制台,比如输出mrDeng这个对象
3、修改对象属性
修改对象的属性也是很简单
var mrDeng = { name: "MrDeng", age: 40, sex: "male", health:100, smoke: function(){ console.log("I am smoking ! cool!!!"); this.health --; }, drink: function(){ console.log("I am drink"); this.health ++; } } mrDeng.sex = 'female'; // 改性别 console.log(mrDeng.sex); // female
4、删除对象属性
delete
删除对象的属性必须要借助一个操作符号 delete
语法: delete 对象名.属性名;
var mrDeng = { name: "MrDeng", age: 40, sex: "male", health: 100, smoke: function(){ console.log("I am smoking ! cool!!!"); this.health --; }, drink: function(){ console.log("I am drink"); this.health ++; } } delete mrDeng.age; // 删除属性成功返回true console.log(mrDeng); // {name: "MrDeng", sex: "male", health: 100, smoke: ƒ, drink: ƒ} console.log(mrDeng.age); // age属性被删除后,再访问age返回undefined
注意一个小问题
1. 当一个变量没经过声明就使用会报错,
2. 当一个对象的没有这个属性就访问不会报错,会打印undefined
var mrDeng = { name: "MrDeng", age: 40, sex: "male", health: 100, smoke: function(){ console.log("I am smoking ! cool!!!"); this.health --; }, drink : function(){ console.log("I am drink"); this.health ++; } } console.log(mrDeng.abc); // 没有abc属性返回undefined
学习了对象的增删改查基本操作,写一个小例子
var deng = { prepareWife: "第二个女朋友", name: "laodeng", sex: "male", girlFriend: "第一个女朋友", wife: "", divorce: function(){ delete this.wife; this.girlFriend = this.prepareWife; }, getMarried: function(){ this.wife = this.girlFriend; }, changeGf: function (someone){ this.prepareWife = someone; } } /** * getMarried 结婚的意思 * * deng.girlFriend 准备结婚的女朋友名 * deng.getMarried(); 结婚修改wife属性值,属性值是girlFriend * deng.wife 结婚后,妻子名 * */ deng.getMarried(); // 结婚修改wife属性值,属性值是girlFriend console.log('妻子: ' + deng.wife); // 妻子: 第一个女朋友 /** * divorce 离婚的意思 * * deng.divorce() 每次离婚的时候两个环节, * 1.第一删除wife属性, * 2.第二换新女朋友,gerlFriend属性值换成prepareWife * 查看deng.wife,离婚后没有妻子了,打印deng.wife属性输出undefined * 查看deng.girlFriend准备结婚的女朋友,输出第二个女朋友 * */ deng.divorce(); // 离婚方法:删除wife属性,女朋友gerlFriend属性换新值prepareWife console.log('妻子: ' + deng.wife); // undefined console.log(deng.girlFriend); // 第二个女朋友 /** * 再结婚getMarried() * * deng.girlFriend 准备结婚的女朋友名 * deng.getMarried(); 又结婚了修改wife属性,属性的值修改为prepareWife * 结婚后查看deng.wife妻子名,输出,第二个女朋友 * */ deng.getMarried(); // 再结婚了修改wife属性,值为prepareWife console.log('妻子: ' + deng.wife);// 妻子: 第二个女朋友 /** * 换新女朋友,传一个实参"第三个新女朋友" * * deng.changeGf("第三个新女朋友"); // 重新换一个准备结婚的女朋友 * console.log('妻子: ' + deng.wife);// 离婚前打印妻子名没有变,妻子: 第二个女朋友 * */ deng.changeGf("第三个新女朋友"); // 传一个参数:第三个新女朋友 console.log('妻子: ' + deng.wife); // 妻子: 第二个女朋友 /** * divorce() 第二次离婚 * getMarried() 离婚后又结婚,这是第三次 * * deng.divorce()又离婚了还是两个环节 * 1.把wife删除了 * 2.换新女朋友 * 离婚后打印deng.wife属性输出undefined * * deng.getMarried();又结婚了 * 查了deng.wife妻子:第三个新女朋友 * */ deng.divorce(); console.log('妻子: ' + deng.wife); // 妻子: undefined deng.getMarried(); console.log('妻子:'+ deng.wife);// 妻子:第三个新女朋友 console.log(deng); //{prepareWife: "第三个新女朋友", name: "laodeng", sex: "male", girlFriend: "第三个新女朋友", divorce: ƒ, …}
三、对象的创建方法 [重点环节之一]
第一种创建方法:var obj = {}
plainObject 翻译过来叫对象字面量或者叫对象直接量,以后数组直接量、正则直接量都这么来叫的
第二种创建方法:构造函数创建方法(分两个分支)
1)系统自带的构造函数 var obj = new Object()
2)自定义
第三种创建方法
1、系统自带的构造函数object()
Object() 就是一个函数,函数可以执行,然而执行这个函数没有什么用,
想通过构造函数产生对象,构造方法前面加上一个new new Object() 就能返回一个对象,返回的对象也是通过 return 返回的,拿一个变量(obj)来接收这个方法产生的对象
var obj = new Object();
系统自带这个 Object() 构造函数相当于一个工厂,
这个工厂可以批量的生产对象,他生产出的对象每个都长的完全一样,但是彼此独立,
就像一个工艺品生产流程一样,每个工艺品都是一样的但彼此间是独立的,这是构造方法的基本定义
Object()系统自带构造函数产生的对象,和字面量对象没有任何区别是一样的?这两种写方法并没有什么区别是一样的
var obj = new Object(); // 系统自带构造函数产生的对象 var obj = {} // 字面量定义对象
Object() 就像一个工厂一样,执行一次就生产一个对象,并且每次执行生产出的对象都一模一样且独一无二彼此独立,长相一样,功能可能也一样,但就是两个人
var obj1 = new Object(); var obj2 = new Object();
其实系统提供的构造函数有很多,
比如 Array()、Number() 都是系统提供的构造函数,通过他们也能构造出对象来,后面学包装类。
PS:
单引号双引号表示的意思都是字符串,为了更好的和后端PHP配合最好用单引号,PHP是没有双引号的(实际上PHP双引号功能比较丰富)
单引号和双引号的配合:如果在单引号里面写一个单引号用转义字符 ,一般都是单引号配双引号,双引号配合单引号
var name1 = 'ab\'c'; // 可以使用转义字符 var name2 = "ab'c"; // 单引号配双引号 var name3 = 'ab\"c'; // 双引号配合单引号 console.log(name1); // ab'c console.log(name2); // ab'c console.log(name3); // ab"c
给系统构造函数构造出的对象加属性、加方法
1. 不见得非得在对象构造出来的的时候,把属性和方法都弄齐全了
2. 在外部通过增加属性的方式来增加方法(比如下面的say方法),属性后面写等号。冒号是对象字面量形式里面的写法
var obj = new Object(); obj.name = 'abc'; obj.sex = "female"; obj.say = function(){}
JS语句和其它语言的区别和特点(有必要说一下)
js语言里的对象是所有语言里面最灵活最自然的,其他语言的对象生成,比如java、c++需要一个类,通过这个类作为一个模板来批量生产对象。
js有构造函数也相当于这个类,但js不同的是,同样是有模板生产成对象,但java、c++生成的对象是死的,就是一个人生出来就不能变了,不能多加技能、多加属性也不能减少属性。
js完全是灵活的,更像是一个自然的人生出来的过程,生出来之后可以后天增加方法,后天改变方法,后天删除方法,js才是最自然的对象。
2、自定义构造函数
有系统构造的函数,我们也可以定义出自己的构造函数,我们自己的构造函数构造对象才是重点
1. 自定义的构造函数结构上,和函数没有任何区别
2. 我们想通过自定义的构造函数构造出对象,必须借助一个操作符 new
function Person(){} var LiLi = new Person(); // 用new操作符构造一个对象
new操作符后面后面的 Person() 也叫Person执行,也会把函数里面的代码逐行执行,为什么加了new这个 Person 执行就返回一个对象了呢?
下面会详细探究构造函数的内部原理,先记住有new就可以生成一个对象
自定义函数生成的对象 和 系统自带的构造函数生成的对象,基本上没有区别
function Person(){} var LiLi = new Person(); console.log(LiLi); // 生成的是一个空对象 Person {}
new Person() 构造函数生成的是一空对象,构造函数构造完对象之后,一样的新增属性、方法
function Person(){} var LiLi = new Person(); console.log(LiLi); // Person {} LiLi.name = "rose"; // 增加一个name属性 console.log(LiLi.name); // rose
然而真正的用法并不是这样用
先说一下自定义构造函数书写的规范的问题,由于构造函数的写法跟正常函数真没什么大区别,编写代码的时候为了区分他们
1. 构造函数命名的时候严格符合大驼峰式规则(TheFirstName)但凡是个单词首字母都大写
2. 普通函数是小驼峰式规则(theFirstName)第一个单词首字母不大写,后面单词首字母大写
这是人为的不是语法规定的,因为只要首字母大写,后面同事一看命名规则就知道是构造函数了
3、自定义函数很重要,什么是自定义呢?
一个工厂在加工的时候肯定有些自定义的预设环节,比如构造一个车
function Car(){ } var car = new Car();
工厂会基本上加工出一个车的雏形出来,然后让我自己去选配
每一辆车都的品牌、车高、车长、车的重量四个属性,这些属性都是一样的,每一辆生产出来的车都具备了四个属性
function Car(){ this.name = "BMW"; // 品牌 this.height = "1400"; // 高 this.lang = "4900"; // 长 this.weight = "1000"; // 重量 } var car = new Car(); var car1 = new Car(); console.log(car); // Car {name: "BMW", height: "1400", lang: "4900", weight: "1000"} console.log(car1); // Car {name: "BMW", height: "1400", lang: "4900", weight: "1000"}
this.name = "BMW"; 构造函数里面的this可以理解成是我的意思,当前执行的时候就是当前的我。new操作后就是我的品牌、我的高度、我的长度...
car和car1是通过同一个构造函数生产出不同的对象,car和car1是完全不同的两辆车,虽然长的一样,打印car和car1都是一样的
car和car1是完全不同的两辆车,虽然拥有同样的属性,但是他两的属性可以互通吗,其中一个改另外一个改吗?
1. 两个对象各改各的属性,谁也没影响谁,
2. 也就是一个工厂车间生产出的对象,每个对象都一样,但彼此是独立的
function Car(){ this.name = "BMW"; // 品牌 this.height = "1400"; // 高 this.lang = "4900"; // 长 this.weight = "1000"; // 重量 } var car = new Car(); var car1 = new Car(); car.name = "梅赛德斯"; car1.name = "奇瑞"; console.log(car); // Car {name: "梅赛德斯", height: "1400", lang: "4900", weight: "1000"} console.log(car1); // Car {name: "奇瑞", height: "1400", lang: "4900", weight: "1000"}
车也有磨损,
1. 给车加一个磨损值 health 属性,
2. 加一个 run 方法,每一次调用 run 方法,车的磨损 health 值(健康值)都会下降
function Car(){ this.name = "BMW"; this.height = "1400"; this.lang = "4900"; this.weight = 1000; this.health = 100; this.run = function(){ this.health --; } } // 1. 一个工厂生产出不同的对象 var car = new Car(); var car1 = new Car(); // 2. 不同的对象通过不停的调用自己的方法 car.run(); car.run(); car.run(); car1.run(); // 3. 发生了health属性上的不同 console.log(car.health); // 97 console.log(car1.health); // 99
两个car对象都是通过同一个车间生成出来的,但两个对象都在不断调用自己不同的方法,而改变自己的属性,最后长时间会变的很不一样
问题天使
var Car = new Car() 变量名Car 和 构造函数名Car,首字母都大写,两个Car是一样的,走预编译环节互相覆盖
var car = new Car() 变量名car首字母小写 和 构造函数名Car首字母大写是两个不同的东西
a变量和A变量是两个变量,但是在十年前之前是不行的,现在可以了
加点更鲜活的东西,
一个车间生产出来的车肯定有他的共性,比如长、宽、高、重量是一样的,但是 颜色 是可以通过参数的方式让用户自己来选
function Car(color){ this.color = color; // this.color和color这两个重名无所谓,this.color是this对象里面的,color是外部变量 this.name = "BMW"; this.height = "1400"; this.lang = "4900"; this.weight = 1000; this.health = 100; this.run = function(){ this.health --; } } var car = new Car("red"); var car1 = new Car("green"); console.log(car); // Car {color: "red", name: "BMW", height: "1400", lang: "4900", weight: 1000, …} console.log(car1); // Car {color: "green", name: "BMW", height: "1400", lang: "4900", weight: 1000, …}
再模拟写一个Student构造函数(不习惯说是类,说构造函数),
Student是生产的学生的,name、age、sex这些属性都不一样需要留一个接口
function Student(name ,age ,sex){ this.name = name; this.age = age; this.sex = sex; this.grade = 2017; } var ixiGua = new Student("小西瓜" ,36 ,"female"); var potato = new Student("小土豆" ,18 ,"female"); console.log(ixiGua); // Student {name: "小西瓜", age: 36, sex: "female", grade: 2017} console.log(potato); // Student {name: "小土豆", age: 18, sex: "female", grade: 2017}
有固定的、有自己填写的,每一个对象之间是彼此独立的,调用多个构造方法能产生多个独一无二的对象
四、构造函数的内部原理
1. 在函数体最前面隐式的加上this = {}
2. 执行 this.xxx = xxx;
3. 隐式的返回this
为什么 this 能决定生产流程呢,生产流程里面为什么每句都要加this呢?
这个this是第一人称,为什么放在构造函数里面好使的,是有一个内部原因的。
构造函数里面有一个非常重要的三段式,是构造函数能构造出对象的基础原理,很简单就三条。
构造函数能构造出对象有一个前提,是必须加new操作符,有了new之后本来是函数,new 函数就能产生构造函数的功能。
构造函数调用new操作符之后(三部都是隐式的)
第一步:在函数逻辑的最顶端隐式的生成一个 var this = {} 这个this是一个空对象
第二步:有了 var this = {} ,说明AO里就有个 this: {} 对象,然后往AO的this对象里面依次加 this: { name : LiLi, age : 36... }
第三部:AO里面的this该填写的写完了,最后一步会隐式的返回this return this
对象就是这样环节一环一环的生成的,就是这隐式的三部
// 第二步:有了"var this = {}"说明AO里有个this对象,然后生成流程里的"this.name、this.age"等就往this对象里依次增加属性 // AO{ // this:{ // name : "fang", // age : 36, // sex : "female", // grade : 2017 // } // } function Student(name ,age ,sex){ // var this = {} 第一步:有了new之后再函数的最顶端,隐式的创建生成一个空对象 this.name = name; this.age = age; this.sex = sex; this.grade = 2017; // return this; 第三部: 最后一步会隐式把构造好的this对象给return出去 } var student = new Student("fang" ,36 ,"female"); console.log(student); // Student {name: "fang", age: 36, sex: "female", grade: 2017}
第一步 var this = {} 现在可以先这么理解,但还不最终的形式,但意思是一样的,最终的形式要更加完美一些,学完原型之后回过头来再学
再写一个构造函数Person
function Person(name, height){ this.name = name; this.height = height; this.say = function(){ // say方法属于对象,里面的这个this.say的this代表的是第一人称我,和外面的this不是一回事。外面的this在new操作符后必须发生隐式三步运算 console.log(this.say); } } console.log(new Person("fang" ,160).name); // fang
知道构造函数隐式三段式的流程,我们显示的模拟出这三段流程
function Person(name, height){ var that = {}; // 知道隐式的原理,这里显式的模拟 var that = {} that.name = name; that.height = height; return that;// 显式的返回that } // person直接等于Person("fang" ,162),不用new操作,因为new完之后也是出现隐式三步,这样模拟的"系统构造函数:构造方法也是成立的。 var person = Person("fang" ,162); var person1 = Person("rose" ,170); console.log(person); // {name: "fang", height: 162} console.log(person1); // {name: "rose", height: 170}
虽然这样也行,但不选择这样用,只是模拟一下,因为这里面有更深的层次是模拟不了的。
回归系统的构造函数
系统构造函数里面隐式的返回 return this ,
如果显式的返回一个空对象 return {} ,最后的结果是什么?
function Person(name, height){ this.name = name; this.height = height; this.say = function(){ console.log(this.name); } return {}; // 显式的返回一个空对象,代替系统隐式的return this } var person = new Person("fang" ,162); var person1 = new Person("rose" ,170); // 隐式的在逻辑的最后一位,显式的写出来,隐式的必然没有用了,返回空对象 console.log(person); // {} console.log(person1); // {}
显式的 return {} 能够代替隐式 return ,显式的返回一个空对象是可以的
但是return的是一个原始值数字123 return 123 是不允许的,但是这样也不会报错,这是另一个冷门知识点
function Person(name, height){ this.name = name; this.height = height; this.say = function(){ console.log(this.name); } return 123; } /** * return 123; * 虽然return的数字123是原始值,返回的还是正常的this对象, * 系统有这样的机制只要是new操作,可以捣乱但是返回的值必须是对象,数组、function都行,就是不能返回原始值。 * new操作了就不能返回原始值,如果写了原始值就会自动忽略掉,强制返回对象 * 有new操作了就不可能返回原始值,这是个冷知识点。 * */ var person = new Person("fang", 162); var person1 = new Person("rose", 170); console.log(person); // Person {name: "fang", height: 162, say: ƒ} console.log(person1); // Person {name: "rose", height: 170, say: ƒ}
如果问构造函数怎么实现的,回答这三段论,
1. 隐式的创建 var this={},
2. 最后隐式的返回 this,
3. 然后形成对象
五、包装类
String();
Boolean();
Number();
首先铺垫一下,
数字是原始值,原始值不能有属性和方法,属性和方法只有对象才能有,这是对象独特的东西。
对象包括对象自己、数组、function这些都算对象,但是原始值是坚决不能算到对象里面的,原始值是没有资格有属性和方法的,原始值只是一个值,作为自己独立的个体存在。
我们说数字都是原始值是不对的,数字不都是原始值,只有原始值数字才是原始值,
数字分两种数字,字符串分两种字符串,在js里面对变量的灵活程度是空前的高。
这是原始值数字,数字类型的数字123
var num = 123;
还有一种数字 new Number( 123 ) ,看到有 new 这一定是构造函数,还是不是123了 ?
var num = new Number(123); console.log(num); // Number {123}
返回的是对象的形式 Number {123} 格式比较复杂,虽然里面是123,但是现在变成了对象123
变成对象123就能加属性了,因为只有对象能加属性,
1. num加属性abc,值等于字符串"a",再打印 num.abc 属性就能返回"a"
2. 打印num输出 Number {123, abc:"a"} 是一个对象,里面有abc属性还有123
var num = new Number(123); num.abc = "a"; // 加属性abc,值等于a console.log(num.abc); // a console.log(num);// Number {123, abc:"a"}
这样的数字能参与运算吗,还有数字的特性吗?
1. 完全能运算,但是运算后,又回归成原始的数又不是对象了
2. 乘完后又回归成原始值的数字246不是对象了
var num = new Number(123); console.log(num * 2); console.log(num); // 246
数字的对象能参与运算,参与完了之后他又成数字了,
但不参与运算加个属性、加个方法它又能当对象使,字符串、布尔类型完全一致。
字符串也能够像对象一样任意的操作,new出来的都是可以的叫 字符串类型的对象 或者叫 字符串对象
var str = new String("Li"); str.a = "English"; // 加一个a属性,赋值'English' console.log(str.a); // 访问a属性输出English str.sayValue = function(){ // 给字符串加一个方法,这个方法能返回属性a return this.a; } console.log(str.sayValue());// English
var num = new Number( 123 ); 数字类型对象或对象类型的数字
var str = new String( "abcd" ); 字符串对象
布尔类型对象也能进行运算
var bool = new Boolean('true'); console.log(bool); // Boolean {true} 它是一个对象也能进行运算
PS:
布尔是个人,发明了逻辑真和假,有了真和假才有了计算机的底层结构 0、1
null,nudefined 它俩是原始值,它俩不可以有属性,加属性就报错 ,系统提示 Cannot set property 意思是不能设置这个属性
undefined.abc = 123; // Uncaught TypeError: Cannot set property 'abc' of undefined null.abc = "abc"; // Uncaught TypeError: Cannot set property 'abc' of null
数字有正常的“原始值数字”和“数字对象”,
1. 原始值数字,不能有属性和方法,
2. 数字对象,可以有属性和方法,这些在js里面有什么用呢?
看下面字符串"abcd"是原始值,原始值不能有属性和方法,现在 str.length 返回4,是能访问字符串的长度的
var str = "abcd"; console.log(str.length); // 4
但是明确规定原始值是没有属性和方法, length 属性是哪里来的呢?
再看字符串"abcd",能给原始值赋一个属性 abc = "a" 吗?
var str = "abcd"; str.abc= "a"; // 给字符串赋值一个属性 abc="a" console.log(str.abc); // 访问这个abc属性返回undefined
理论上不行,但是赋值后也没有报错,
没有报错说明就已经赋值进去了,能赋值进去就应该能访问,在访问没有这个属性返回undefined
字符串"abcd"的这一系列过程是怎么回事呢?
1. 首先记住一个结论,原始值是坚决不能有属性和方法的,
2. 但是为什么能调用呢?因为经历了一个过程叫 包装类
var num = 4; num.len = 3; console.log(num.len); // undefined
学习完 包装类 就进一步了解js了,在js里面一些非常匪夷所思的用法就都知道了
为什么原始值不能用属性还能加属性?
在原始值调用属性的时候(无论是赋值还是查找),首先原始值自己不能有属性,但是系统会隐式的发生一个过程
var num = 4; num.len = 3; // new Number(4).len = 3; // 系统隐式的新建一个数字对象, // 完后delete删除这个数字对象 console.log(num.len); // 再访问num.len // 系统会再一次隐式一个对象 new Number(4).len // 没有len这个属性所以返回undefined
变量num是原始值,不能加属性(len)会么办?
1. 系统会隐式的新建一个数字对象 new Number(4) ,把num放进去(把4放进去)之后,
2. 再让数字对象的len属性等于3 new Number(4).len = 3 ,就是隐式的新建一个数字对象,让数字对象的 len 属性等于3,来弥补操作的不足,
3. 然后这步完事了之后,直接销毁delete
下一次在访问 num.len
4. 系统会再一次 new Number(4) ,然后访问 new Number(4).len len属性,
5. 这一次 new Number 和上面 new Number 不是一回事,是两个对象完全不一样,
6. 上面的 len = 3 完后销毁了,这一次重新new出来的对象没有len属性,一个对象没有这个属性必然返回是undefined
字符串赋值是系统帮着实现这个赋值操作,然后字符串取值系统也帮着实现这个操作,实际上都不是表面看起来这个样子,这个隐式的中间环节叫做包装类。
所以有面试这样考
数组是可以截断操作的,因为数组本身就有 length 属性,这个 length 除了可以访问,还可以被赋值
var arr = [1,2,3,4,5,6]; console.log(arr.length); // 访问数组的length属性返回 6 arr.length = 2; // 属性length赋值为2,会把数组截断只剩2位 console.log(arr); // 数组被截断了返回两个值 [1, 2]
基于数组的理论会这样考,
字符串也有 length 属性,让字符串length等于2,然后打印字符串结果是什么?
var str = "abcd"; str.length = 2; // 1.系统隐式的 new String('abcd').length = 2 // 2.完后 delete 销毁 console.log(str); // 3. 访问字符串str,跟上面没关系,返回abcd console.log(str.length); // 4
1. 字符就有的length属性,只不过是对象字符串有这个属性
2. str.length 字符串的长度是4
2. 给我们造成了错觉,可以直接用字符串 str.length,其实是 new string().length 的结果抛回来的数
从现在起,我开始谨慎的选择我的生活,不再轻易让自己迷失在各种诱惑里,我心中已经听到来自远方的呼唤,再不需要回过头去,关心身后的种种是非与议论,我已无暇顾及过去,我要向前走。—— 米兰 · 昆德拉