网站备案接入商名称,成都捕鱼网站建设,广州企业年报网上申报入口,500强室内设计公司排名一、认识对象
1.概述
对象#xff08;object#xff09;是 JavaScript 语言的核心概念#xff0c;也是最重要的数据类型。
什么是对象#xff1f;简单说#xff0c;对象就是一组“键值对”#xff08;key-value#xff09;的集合#xff0c;是一种无序的复合数据集合…一、认识对象
1.概述
对象object是 JavaScript 语言的核心概念也是最重要的数据类型。
什么是对象简单说对象就是一组“键值对”key-value的集合是一种无序的复合数据集合。
var obj {foo: Hello,bar: World
};上面代码中大括号就定义了一个对象它被赋值给变量obj所以变量obj就指向一个对象。该对象内部包含两个键值对又称为两个“成员”第一个键值对是foo: Hello其中foo是“键名”成员的名称字符串Hello是“键值”成员的值。键名与键值之间用冒号分隔。第二个键值对是bar: Worldbar是键名World是键值。两个键值对之间用逗号分隔。
2.键名
对象的所有键名都是字符串ES6 又引入了 Symbol 值也可以作为键名所以加不加引号都可以。上面的代码也可以写成下面这样。
var obj {foo: Hello,bar: World
};如果键名是数值会被自动转为字符串。
var obj {1: a,3.2: b,1e2: true,1e-2: true,.234: true,0xFF: true
};obj
// Object {
// 1: a,
// 3.2: b,
// 100: true,
// 0.01: true,
// 0.234: true,
// 255: true
// }obj[100] // true对象的每一个键名又称为“属性”property它的“键值”可以是任何数据类型。如果一个属性的值为函数通常把这个属性称为“方法”它可以像函数那样调用。
var obj {p: function (x) {return 2 * x;}
};obj.p(1) // 2如果属性的值还是一个对象就形成了链式引用。
var o1 {};
var o2 { bar: hello };o1.foo o2;
o1.foo.bar // hello对象的属性之间用逗号分隔最后一个属性后面可以加逗号trailing comma也可以不加。
var obj {name: aaa,
}属性可以动态创建不必在对象声明时就指定。
var obj {};
obj.foo 1;
obj.bar name;3.对象的引用
如果不同的变量名指向同一个对象那么它们都是这个对象的引用也就是说指向同一个内存地址。修改其中一个变量会影响到其他所有变量。
var o1 {};
var o2 o1;o1.a 1;
o2.a // 1o2.b 2;
o1.b // 2如果取消某一个变量对于原对象的引用不会影响到另一个变量。
var o1 {};
var o2 o1;o1 1;
o2 // {}4.表达式还是语句
对象采用大括号表示这导致了一个问题如果行首是一个大括号它到底是表达式还是语句
{ a: 1 }JavaScript 引擎读到上面这行代码会发现可能有两种含义。第一种可能是这是一个表达式表示一个包含foo属性的对象第二种可能是这是一个语句表示一个代码区块里面有一个标签foo指向表达式123。
为了避免这种歧义JavaScript 引擎的做法是如果遇到这种情况无法确定是对象还是代码块一律解释为代码块。
{ console.log(123) } // 123上面的语句是一个代码块而且只有解释为代码块才能执行。
如果要解释为对象最好在大括号前加上圆括号。因为圆括号的里面只能是表达式所以确保大括号只能解释为对象。
({ foo: 123 }) // 正确
({ console.log(123) }) // 报错这种差异在eval语句作用是对字符串求值中反映得最明显。
eval({foo: 123}) // 123
eval(({foo: 123})) // {foo: 123}上面代码中如果没有圆括号eval将其理解为一个代码块加上圆括号以后就理解成一个对象。
二、对象的操作
1.创建对象
对象的创建方法有很多包括三种
对象字面量Object Literal通过{}new Object动态添加属性new 其他类
// 方式一
var obj new Object();
obj.foo 1;
obj.bar abc;
console.log(obj);// 方式二
var obj2 {foo: 1,bar: abc
}
console.log(obj2);// 方式三
var obj3 new Abc();function Abc() {this.foo 1;this.bar abc;
}
console.log(obj3);目前我们主要掌握对象字面量的方式后续我们学习其他两种方式。
对象的使用过程包括如下操作
访问对象的属性修改对象的属性添加对象的属性删除对象的属性
2.访问对象
读取对象的属性有两种方法一种是使用点运算符还有一种是使用方括号运算符。
var obj {p: Hello World
};obj.p // Hello World
obj[p] // Hello World请注意如果使用方括号运算符键名必须放在引号里面否则会被当作变量处理。
var obj {foo: 1,bar: 2
}
var foo bar;
obj.foo; // 1
obj[foo]; //2方括号运行我们在定义或者操作属性时更加的灵活
var message 吃饭 树胶;
var obj {name: abc,[message]: def
}
console.log(obj[message]);//def方括号运算符内部还可以使用表达式。
var obj {12: 34,0.7: 56
}
obj[0.7]// 56
obj[102]//343.添加对象的属性赋值
点运算符和方括号运算符不仅可以用来读取值还可以用来赋值。
var obj {};obj.foo Hello;
obj[bar] World;4.查看所有属性
查看一个对象本身的所有属性可以使用Object.keys方法。
var obj {key1: 1,key2: 2
};Object.keys(obj);
// [key1, key2]5.属性的删除delete 命令
delete命令用于删除对象的属性删除成功后返回true。
var obj { p: 1 };
Object.keys(obj) // [p]delete obj.p // true
obj.p // undefined
Object.keys(obj) // []上面代码中delete命令删除对象obj的p属性。删除后再读取p属性就会返回undefined而且Object.keys方法的返回值也不再包括该属性。
注意删除一个不存在的属性delete不报错而且返回true。
var obj {};
delete obj.p // true上面代码中对象obj并没有p属性但是delete命令照样返回true。因此不能根据delete命令的结果认定某个属性是存在的。
只有一种情况delete命令会返回false那就是该属性存在且不得删除。
var obj Object.defineProperty({}, p, {value: 123,configurable: false
});obj.p // 123
delete obj.p // false上面代码之中对象obj的p属性是不能删除的所以delete命令返回false。
另外需要注意的是delete命令只能删除对象本身的属性无法删除继承的属性。
var obj {};
delete obj.toString // true
obj.toString // function toString() { [native code] }上面代码中toString是对象obj继承的属性虽然delete命令返回true但该属性并没有被删除依然存在。这个例子还说明即使delete返回true该属性依然可能读取到值。
6.属性是否存在in 运算符
in运算符用于检查对象是否包含某个属性注意检查的是键名不是键值如果包含就返回true否则返回false。它的左边是一个字符串表示属性名右边是一个对象。
var obj { p: 1 };
p in obj // true
toString in obj // truein运算符的一个问题是它不能识别哪些属性是对象自身的哪些属性是继承的。就像上面代码中对象obj本身并没有toString属性但是in运算符会返回true因为这个属性是继承的。
这时可以使用对象的hasOwnProperty方法判断一下是否为对象自身的属性。
var obj {};
if (toString in obj) {console.log(obj.hasOwnProperty(toString)) // false
}7.对象的遍历
对象的遍历迭代表示获取对象中所有的属性和方法。
Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组
遍历方式一普通for循环
var infoKeys Object.keys(info)for (var i 0; i infoKeys.length; i) {var key infoKeys[i]var value info[key]console.log(key: ${key}, value: ${value})}遍历方式二for in 遍历方法
for (var key in info) {var value info[key]console.log(key: ${key}, value: ${value})
}// 对象不支持: for..of..: 默认是不能遍历对象
// for (var foo of info) {
// }for...in循环有两个使用注意点。
它遍历的是对象所有可遍历enumerable的属性会跳过不可遍历的属性。它不仅遍历对象自身的属性还遍历继承的属性。
如果继承的属性是可遍历的那么就会被for...in循环遍历到。但是一般情况下都是只想遍历对象自身的属性所以使用for...in的时候应该结合使用hasOwnProperty方法在循环内部判断一下某个属性是否为对象自身的属性。
var person { name: 老张 };for (var key in person) {if (person.hasOwnProperty(key)) {console.log(key);}
}
// name三、对象的数据结构
1.栈内存和堆内存
我们知道程序是需要加载到内存中来执行的我们可以将内存划分为两个区域栈内存和堆内存。
原始类型占据的空间是在栈内存中分配的对象类型占据的空间是在堆内存中分配的 2.值类型和引用类型
原始类型的保存方式在变量中保存的是值本身
所以原始类型也被称之为值类型
对象类型的保存方式在变量中保存的是对象的“引用”
所以对象类型也被称之为引用类型 3.对象的一些现象
现象一: 两个对象的比较 var obj1 {}var obj2 {}console.log(obj1 obj2)现象二: 引用的赋值
var info {name: why,friend: {name: kobe}
}var friend info.friend
friend.name james
console.log(info.friend.name) // james现象三: 值传递
function foo(a) {a 200
}
var num 100
foo(num)
console.log(num) // 100现象四: 引用传递, 但是在函数中创建了一个新对象, 没有对传入对象进行修改
function foo(a) {a {name: why}}
var obj {name: obj
}
foo(obj)
console.log(obj)现象五: 引用传递, 但是对传入的对象进行修改
function foo(a) {a.name why
}var obj {name: obj
}
foo(obj)
console.log(obj)四、this关键字
1.为什么需要this
在常见的编程语言中几乎都有this这个关键字Objective-C中使用的是self但是JavaScript中的this和常见的面向对象 语言中的this不太一样
常见面向对象的编程语言中比如Java、C、Swift、Dart等等一系列语言中this通常只会出现在类的方法中。也就是你需要有一个类类中的方法特别是实例方法中this代表的是当前调用对象
但是JavaScript中的this更加灵活无论是它出现的位置还是它代表的含义
我们来看一下编写一个obj的对象有this和没有this的区别
//没有this
var obj {name: code!mq,eating: function () {console.log(obj.name 正在吃饭);},sleep: function () {console.log(obj.name 正在睡觉);}
}
obj.eating();
// 有this
var obj {name: code!mq,eating: function () {console.log(this.name 正在吃饭);},sleep: function () {console.log(this.name 正在睡觉);}
}
obj.eating();2.this指向什么
函数中是有一个this的变量, this变量在大多数情况下会指向一个对象
情况一: 如果普通的函数被默认调用, 那么this指向的就是window
function sayHello(name) {console.log(this);
}
sayHello(code!mq);情况二: 如果函数它是被某一个对象来引用并且调用它, 那么this会指向这个对象(调用的那个调用)
var obj {name: code!mq,running: function() {console.log(this)// console.log(obj)// console.log(this obj)}
}
obj.running()后续我们还会学习其他也会给大家总结this的规律详见高级篇
五、类和对象
1.类和对象的思维方式
我们来思考一个问题如果需要在开发中创建一系列的相似的对象我们应该如何操作呢
比如下面的例子
游戏中创建一系列的英雄英雄具备的特性是相似的比如都有名字、技能、价格但是具体的值又不相同学生系统中创建一系列的学生学生都有学号、姓名、年龄等但是具体的值又不相同
当然一种办法是我们创建一系列的对象
var p1 {name: zhangsan,age: 18,height: 1.88
}var p2 {name: lisi,age: 19,height: 1.85
}var p3 {name: wangwu,age: 29,height: 1.65
}这种方式有一个很大的弊端创建同样的对象时需要编写重复的代码
我们是否有可以批量创建对象但是又让它们的属性不一样呢
2.创建对象的方案 – 工厂函数
我们可以想到的一种创建对象的方式工厂函数
我们可以封装一个函数这个函数用于帮助我们创建一个对象我们只需要重复调用这个函数即可工厂模式其实是一种常见的设计模式
// 工厂函数(工厂生产student对象) - 一种设计模式
// 通过工厂设计模式, 自己来定义了一个这样的函数
function createStudent(name, age, height) {var stu {}stu.name namestu.age agestu.height heightstu.running function() {console.log(running~)}return stu
}var stu1 createStudent(why, 18, 1.88)
var stu2 createStudent(kobe, 30, 1.98)
var stu3 createStudent(james, 25, 2.05)
console.log(stu1)
console.log(stu2)
console.log(stu3)3.认识构造函数
工厂方法创建对象有一个比较大的问题我们在打印对象时对象的类型都是Object类型
但是从某些角度来说这些对象应该有一个他们共同的类型下面我们来看一下另外一种模式构造函数的方式
我们先理解什么是构造函数
构造函数也称之为构造器constructor通常是我们在创建对象时会调用的函数在其他面向的编程语言里面构造函数是存在于类中的一个方法称之为构造方法但是JavaScript中的构造函数有点不太一样构造函数扮演了其他语言中类的角色
也就是在JavaScript中构造函数其实就是类的扮演者
比如系统默认给我们提供的 Date 就是一个构造函数也可以看成是一个类在ES5之前我们都是通过function来声明一个构造函数类的之后通过new关键字来对其进行调用在ES6之后JavaScript可以像别的语言一样通过class来声明一个类
// JavaScript已经默认提供给了我们可以更加符合JavaScript思维方式(面向对象的思维方式)的一种创建对象的规则
// 在函数中的this一般指向某一个对象
/*如果一个函数被new操作符调用1.创建出来一个新的空对象2.让this指向这个空对象3.执行函数体的代码块4.如果没有明确的返回一个非空对象, 那么this指向的对象会自动返回*/
function coder(name, age, height) {this.name namethis.age agethis.height heightthis.running function() {console.log(running~)}
}// 在函数调用的前面加 new 关键字(操作符)
var stu1 new coder(why, 18, 1.88)
var stu2 new coder(kobe, 30, 1.98)
console.log(stu1, stu2)那么类和对象到底是什么关系呢
2.类和对象的关系
那么什么是类构造函数呢
现实生活中往往是根据一份描述/一个模板来创建一个实体对象的.编程语言也是一样, 也必须先有一份描述, 在这份描述中说明将来创建出来的对象有哪些属性(成员变量)和行为(成员方法)
比如现实生活中我们会如此来描述一些事物
比如水果fruits是一类事物的统称苹果、橘子、葡萄等是具体的对象比如人person是一类事物的统称而Jim、Lucy、Lily、李雷、韩梅梅是具体的对象
3.JavaScript中的类ES5
我们前面说过在JavaScript中类的表示形式就是构造函数。
JavaScript中的构造函数是怎么样的
构造函数也是一个普通的函数从表现形式来说和千千万万个普通的函数没有任何区别那么如果这么一个普通的函数被使用new操作符来调用了那么这个函数就称之为是一个构造函数
如果一个函数被使用new操作符调用了那么它会执行如下操作
在内存中创建一个新的对象空对象这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性后面详细讲构造函数内部的this会指向创建出来的新对象执行函数的内部代码函数体代码如果构造函数没有返回非空对象则返回创建出来的新对象
接下来我们可以用构造函数的方式来实现一下批量创建学生。
4.创建对象的方案 – 构造函数类
我们来通过构造函数实现一下
function Person(name, age, address) {this.name name;this.age age;this.address address;this.eatting function () {console.log(this.name 吃饭饭);}
}
var p1 new Person(zhangsan, 12, gd);
var p2 new Person(lis, 16, sh);这个构造函数可以确保我们的对象是有Person的类型的实际是constructor的属性这个我们后续再探讨
事实上构造函数还有很多其他的特性
比如原型、原型链、实现继承的方案比如ES6中类、继承的实现
5.额外补充-全局对象window
浏览器中存在一个全局对象object - window
作用一: 查找变量时, 最终会找到window头上
作用二: 将一些浏览器全局提供给我们的变量/函数/对象, 放在window对象上面
作用三: 使用var定义的变量会被默认添加到window上面
console.log(window)// 使用var定义变量
var message Hello Worldfunction foo() {// 自己的作用域// abc()// alert(Hello World)console.log(window.console console)// 创建一个对象// var obj new Object()console.log(window.Object Object)// DOMconsole.log(document)// window.messageconsole.log(window.message)
}
foo()6.额外补充-函数也是对象
// 定义原始类型的变量
var name why
var age 18// 定义对象类型的变量
// 地址 - 指针 - 引用
var obj {} // 堆内存
var foo function() {} // 堆内存
function bar() {} // 堆内存console.log(typeof obj) // object
console.log(typeof foo) // function - object// var stu new Student() // stu是一个Student - Person// 引申一些别的知识(了解)
var info {}
info.name abcfunction sayHello() {
}
sayHello.age 18
console.log(sayHello.age)function Dog() {}
// 构造函数上(类上面)添加的函数, 称之为类方法
Dog.running function() {}
Dog.running()