对象、包装类
文章目录
对象
1.用已学的知识点,描述一下你心目中的对象。
var mrJason = {
name : "MrJason",
age : 40,
sex : "male",
health : 100,
smoke : function () { // 对象的属性里放函数就叫方法
console.log('I am smoking ! cool!!!');
this.health -- ;
// 不能直接写health-- 因为系统需要知道是哪个属性的health,但是一般不直接写函数名,都是用第一人称 this 比如张杰不会说:张杰很帅 只会说:我很帅 因为使用第一人称
},
drink : function () { // 对象的属性里放函数就叫方法
console.log('I am drink');
this.health ++ ;
},
}
// 方法调用
mrJason.smoke 代表函数的引用
mrJason.smoke() 执行函数smoke // 函数没有return 所以控制台打印undefined
mrJason.health --> 99
2.属性的增、删、改、查
var mrJason = {
name : "MrJason",
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 ++ ;
},
}
// 属性的增
mrJason.wife = "xiena" // 这里需要写值,不写值就成访问了 写完之后访问mrJason就会增加这个属性,可以在控制台写 也可以在mrJason外定义
// 属性的删
delete mrJason.age // 可以在控制台写 也可以在mrJason外写,写完属性就没了
mrJason.age // 打印undefined
// 访问一个不存在的对象属性不报错会打印undefined (如果是没声明的变量,打印会报错)
// 属性的改
mrJason.wife = "xiena111" // 可以在控制台写 也可以在mrJason外写,写完属性值就改变了
// 属性的查
mrJason.wife // 查看wife的值
console.log(mrJason.wife) // 直接打印值也是查的方式
// 练习
var Jason = {
prepareWife : "xiaowang", // 未婚妻
name : zhangjie,
sex : "male",
gf : "xiaoliu",
wife : "",
divorce : function () {
delete this.wife,
this.gf = this.prepareWife;
},
getMarried : function () {
// 每次结婚的时候会把girlfriend变成wife 离婚的时候把wife放到prepareWife里面去
this.wife = this.gf,
},
changePrepareWife : function (someone) { // 传参
this.prepareWife = someone;
// 控制台传参 Jason.changePrepareWife('xiaozhang')
}
}
// 传参也可以写在函数外 Jason.changePrepareWife('xiaozhang')
3.对象的创建方法
字面量
// 对象的创建方法
// 1.var obj = {} plainObject 对象字面量/对象直接量
构造函数
-
系统自带new Object();Array(;Number();Boolean();String0);Date();
// 2.构造函数 // a. 系统自带的构造函数 : Object()、Array()、Number()等 // 构造函数Object()基本定义: // 就是一个可以执行的函数,但执行函数没什么用,如果想通过函数来产生对象的话,系统自带的构造函数就相当于一个工厂,可以批量的生产对象,生产的对象完全一样又彼此独立,就像每一个工艺品一样。 // new Object(): // new 加一个构造函数或者构造方法的执行,它就能通过return返回一个真正的对象。 // 所以需要定义一个变量接收方法产生的对象(return返回的) var obj = new Object() --> var obj = {} // 这俩一样 没有任何区别 // 属性值很灵活,任意增删改查 var obj = new Object(); obj.name = 'abc'; obj.sex = "male"; // ""和''都是字符串,但是最好使用单引号 obj.say = function () { // 在外部以增加属性的的方法增加函数 }
-
自定义
// b. 自定义 function abc() { } // 构造函数和函数在结构上没有任何区别,函数名可以自定义 // 想通过自己定义的函数构造对象的话,需要借助new操作符才能构造对象。 var person1 = new person(); // person()函数的执行 有new就会生成对象 // c. 构造函数命名规则 : 大驼峰 // 大驼峰式命名规则:每个单词首字母都要大写 TheFirstName // (小驼峰是第一个单词首字母小写,其他字母大大写) theFirstName
-
构造函数
// 方法名和对象名尽量不一样 // 就好比工厂的制造车过程,定义车的属性 function Car() { this.name = "BMW"; // 定义每个车的名字都是宝马 this.height = "1400"; // 宽度 this.lang = "4900"; // 长度 this.weight = 1000; this.health = 100; this.run = function () { // 每次run 车的健康值就会减少 this.health --; } } // 通过同一个构造函数生产出不同的对象,两个对象完全一样,但是彼此独立,可以理解成把Car函数赋值给两个变量了。 var car = new Car(); var car1 = new Car(); // 两个对象是独立的个体,属性值各改各的,互不影响 car.name = "Maserati"; car1.name = "Merz"; // 运行函数更改各自的值,也是互不影响 // 控制台执行 car.run() // 执行car对象的run函数,也就是health -- car.health //查看car的health就是99 car1.health //查看car1的health是100 因为car1没有运行函数 两者互不影响
// 车的颜色可以车主自己选择(传参) function Car(color) { this.color = 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');
Object.create(原型)方法
function Student(name, age, sex) { // 自定义需要传参的属性
this.name = name;
this.age = age;
this.sex = sex;
this.grade = 2022;
}
var student = new Student('zhangsan', 18, 'male'); // 传参
构造函数内部原理
构造函数的基础前提是必须得加new
构造函数隐式三步运算
- 在函数体最前面隐式的加上this = {}
- 执行this.xxx=xxx;
- 隐式的返回this
function Student(name, age, sex) {
// 有了new之后 在逻辑最顶端会生成一个var this = {};
// 产生的AO就会存储这个空对象,传参的属性会存到AO里面的this中
// AO { this : {name : 'Jason', age : 18, sex : 'male'}}
// this会被填充满 构造函数中有的属性this都有了 传的参数就是this的属性值
this.name = name;
this.age = age;
this.sex = sex;
this.grade = 2022;
// return this; // 在函数末尾会隐式的return this 生成this对象
}
var student = new Student('Jason', 18, 'male'); // 传参
function Person()(name,height) {
this.name = name;
this.height = height;
this.say = function () { // 这个方法属于这个对象
console.log(this.say); // 这里的this是上级的第一人称 也就是指代this.say
}
}
new Person(); // 看到new加函数执行 函数内部一定发生隐式三步运算 没new就是正常的函数执行
console.log(new Person('xiaowang',180).name) // 传参之后打印name 不传参没东西给你打印 只会打印undefined
// new Person会返回一个对象 这里是直接利用了 没有定义其他变量接收
function Person()(name,height) { // 一个特殊的构造函数
var taht = {}; // 定义一个显式的变量用于接收属性和参数
that.name = name;
that.height = height;
return that; // 显式返回
}
// 模拟系统函数构造方法
var person = new Person('xiaowang',180); // 可以理解为函数带参数之后赋值给person
var person1 = new Person('xiaozhang',175); // 可以理解为函数带参数之后赋值给person1
function Person()(name,height) {
// var this = {};
this.name = name;
this.height = height;
this.say = function () {
console.log(this.say);
}
return {}; // 如果把下面的隐式返回this改成显式返回空对象会怎样?可以返回数组、对象、函数等,但是不能写原始值(123这种),否则还是默认返回this
// return this;
}
var person = new Person('xiaowang',180); // 打印person就会是空对象
var person1 = new Person('xiaozhang',175); // 打印person1就会是空对象
包装类
属性和方法是对象(对象、数组、函数)特有的东西。
原始值没有方法和属性,是一个独立的个体。
原始值想要赋属性值需要调用包装类
new String();
// str也能像对象一样new一个操作
var str = new String('abcd') // undefined
str.a = 'bcd' // bcd
str.a // bcd
str.sayValue = function () {
returnthis.a
} // function () {return this.a}
str.sayValue() // 加括号是执行函数 输出"bcd"
var arr = [1,2,3,4,5] // 数组本身就有属性length,length不但能访问还能赋值
arr.length // 5
arr.length = 2 // 数组成[1,2]
// 包装类
var str = "abcd";
str.length = 2; // 隐式过程 new String('abcd').length = 2; 然后把2返回给str.length 然后删除自己(new String('abcd').length = 2)
console.log(str); // 这里打印还是原来的str,所以打印结果是abcd,上面的隐式过程只是删除了新建的String('abcd')
console.log(str.length); // 4 注意length是系统自带的属性
// new String('abcd').length
new Boolean();
// undefined和null不可以有属性
undefined.abc = '123' // 报错
null.abc = '123' // 报错
var num = new Number(123);
var str = new String('abcd');
var bol = new Boolean('true');
new Number();
var num = 123; // 123就是原始值数字
var num = new Number(123); // 这里的123是构造函数的123 是在OA这个对象中的123 然后把这个对象赋值给num 123没有属性名 默认属性名是[[PrimitiveValue]](原始值)
num.abc = 'a' // 控制台再num对象中增加abc这个属性并赋值a
// 打印num就会有abc和[[PrimitiveValue]]这两个属性
// 但是如果这个对象进行运算 那对象中的123又会恢复成原始值
num * 2 // 246
// 数字的对象能参与运算,参与完就变成数字了 就不是对象了 字符串和布尔类型也是一样的
// 隐式的中间的环节叫包装类
// 原始值是不可能有属性和方法 但是为什么能调用 是因为包装类
// number没有length属性
var num = 4;
num.len = 3; // 无论赋值还是查找,在原始值调用(num.len)的时候会隐式的发生一个过程
// new Number(4).len = 3; delete // 新建一个数字对象new Number(4),让数字对象的len=3 然后把3返回给num.len 然后把自己删除
console.log(num.len); // 这里打印又访问num.len,也是会新建一个另一个Number
// new Number(4).len // 但是这里并没有赋值操作 一个对象没有属性值打印是undefined
// 这个Number和num.len = 3的操作中生成的Number是两个不同的Number
练习
// 练习
var str = "abc";
str += 1; // abc后面加个1 "abc1"
var test = typeof(str); // test == "string"
if(test.length == 6) { // 自己没有length 但是包装类会给它返回length = 6
test.sign = "typeof的返回结果可能是String"; // 原始值想要赋值需要调用包装类
// 换句话说就是赋值跟没赋一样 这里的隐式过程
// new String(test).sign = "typeof的返回结果可能是String"
}
console.log(test.sign); // 打印的时候再new String(test).sign 但是没值 所以打印undefined
// 1.运行test() 和 new test()的结果分别是什么?
var a = 5;
function test() {
a = 0;
alert(a);
alert(this.a); // 如果不new的话 执行期上下文的this原则上都指向window
var a;
alert(a);
}
test() // 0 5 0
new test() // 0 undefined 0
// 2. 分析下面的JavaScript代码段:
function employee(name,code) {
this.name = "wangli"; // 属性值写死了 没有参数
this.code = "A001";
}
var newemp = new employee("zhangming",'A002');
console.log("雇员姓名:" + newemp.name + "<br>"); // 访问newemp.name的时候还是原来的内容
console.log("雇员代码:" + newemp.code + "<br>"); // 访问newemp.code的时候还是原来的内容
// 输出的结果是(A).(选择一项)
// A. 雇员姓名:wangli 雇员代码:A001
// B. 雇员姓名:zhangming 雇员代码:A002
// C. 雇员姓名:null 雇员代码:null
// D. 代码有错误,无输出结果
//5.闭包+包装类
function Person(name, age, sex) {
var a = 0;
this.name = name;
this.age = age;
this.sex = sex;
function sss() {
a ++;
console.log(a);
}
this.say = sss;
}
var oPerson = new Person(); // 包装类
oPerson.say(); // 1 闭包 子函数共用上级函数中的AO 所以第一次是1 第二次是2
oPerson.say(); // 2
var oPerson1 = new Person(); //产生新的闭包 和上面的互不影响
oPerson1.say(); // 1
// 下面这段js代码执行完毕之后c,y,z的值分别是多少?
// x = 1 y = 4 z = 4
// 预编译:AO {add:function () {return n = n + 3} }
// 注意只有一个add函数 只是返回值不一样 后面的add会覆盖前面的add内容 因为AO中只有一个add
var x = 1, y = z =0;
function add(n) {
return n = n + 1;
}
y = add(x); // 这里调用的add是预编译完了之后的add AO中存储的是return n = n + 3
function add(n) {
return n = n + 3;
}
z = add(x); // 这里调用的add是预编译完了之后的add
arguments是js中函数内置的一个对象,而执行函数方法的实参中值都存储在arguments中
// 下面代码中console.log的结果是[1,2,3,4,5]的选项的是:A、C
// A
function foo(x) {
console.log(arguments)
return x
}
foo(1,2,3,4,5)
// B 没有函数调用 不报错也不执行
function foo(x) {
console.log(arguments)
return x
}(1,2,3,4,5)
// C 立即执行函数
(function foo(x) {
console.log(arguments)
return x
})(1,2,3,4,5)
// 请问以下表达式的结果是什么?
// parseInt(string, radix)接收两个参数,第一个参数是待转换的字符串,第二个参数是范围在2-36中的一个整数,表示几进制,作为基底。例:parseInt(3,8)就是把3以八进制为基底转换成十进制
parseInt(3,8) // 3 3当成八进制的数还是3
parseInt(3,3) // NaN 3当成3进制的数是10 所以不能把3当成3进制数
parseInt(3,2) // NaN 3当成2进制的数是11 所以不能把3当成2进制数
parseInt(3,0) // 3、 写0跟没写一样 会把原来的数返回
// 以下哪些是javascript语言typeof可能返回的结果
A. string // 可
B. array // 不可 array返回function 但没有返回array的
C. object // 可 object返回function
D. null // 不可 历史遗留问题 null返回object 但没有返回null的
// 看看下面alert的结果是什么 考点是a=10和arguments[2] = 10 是不是互相映射 一个改另一个也改
function b(x, y, a) {
arguments[2] = 10; // a一开始参数时3 但是这里又把10赋值给a了
alert(a); // 10 alert是弹出框
}
b(1, 2, 3);
// 如果函数体改成下面,结果又会是什么?
a = 10;
alert(arguments[2]); // 10
function test(x, y, a) {
argument[2] = 10; // argument[2] = 10 ==> a = 10
console.log(a);
}
test(1, 2, 3)
作业
// 8.写一个方法,求一个字符串的字节长度。(提示:字符串有一个方法charCodeAt();一个中文占两个字节,一个英文占一个字节.
// 定义和用法
// charCodeAt()方法可返回指定位置的字符的Unicode编码。这个返回值是0-65535之间的整数。(当返回值是<=255时为英文,当返回值>255时为中文)
// 语法
stringObject.charCodeAt(index)
eg:
<script type="javascript/ text">
var str="Hcllo world!"
console.log(str.charCodcAt(l));//输出101
</script>
// 解答
// 方法一:都默认是占一个字节,然后遇到中文再加1
// 1. 当前字符位的unicode > 255 , 那么该字符字节长度为2
// 2. <= 255 为1
var str = "abda张杰真帅hdaj"
function bytesLength(str) {
var count = str.length;
for(var i = 0, i < str.length, i ++)
if (str.charCodcAt(i) > 255) { // 判断每位i的字符串长度
count ++;
}
return count;
}
// 方法二:判断是大于255还是小于255然后再进行判断
var str = "abda张杰真帅hdaj"
function bytesLength(str) {
var count = 0;
for(var i = 0, i < str.length, i ++)
if (str.charCodcAt(i) > 255) { // 判断每位i的字符串长度
count += 2;
}else {
count ++;
}
return count;
}
// 方法二:判断是大于255还是小于255然后再进行判断
var str = "abda张杰真帅hdaj"
function bytesLength(str) {
var count = 0;
for(var i = 0, i < str.length, i ++)
if (str.charCodcAt(i) > 255) { // 判断每位i的字符串长度
count += 2;
}else {
count ++;
}
return count;
}