Go to comments

JavaScript 对象

对象


对象是一种基础的变量类型,对象和数组、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" 这个属性了

image.png


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: ƒ, …}


三、对象的创建方法 [重点环节之一]


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}

有固定的、有自己填写的,每一个对象之间是彼此独立的,调用多个构造方法能产生多个独一无二的对象


四、构造函数的内部原理


为什么 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. 然后形成对象


五、包装类


首先铺垫一下,

数字是原始值,原始值不能有属性和方法,属性和方法只有对象才能有,这是对象独特的东西。

对象包括对象自己、数组、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

image.png


变成对象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  的结果抛回来的数


从现在起,我开始谨慎的选择我的生活,不再轻易让自己迷失在各种诱惑里,我心中已经听到来自远方的呼唤,再不需要回过头去,关心身后的种种是非与议论,我已无暇顾及过去,我要向前走。—— 米兰 · 昆德拉



Leave a comment 0 Comments.

Leave a Reply

换一张