JavaScript对象
- JavaScript中提供了一个默认的类Object, 我们可以通过这个类来创建对象
- 由于我们是使用系统默认的类创建的对象, 所以系统不知道我们想要什么属性和行为, 所以我们必须手动的添加我们想要的属性和行为
- 如何给一个对象添加属性
对象名称.属性名称 = 值;
- 如何给一个对象添加行为
对象名称.行为名称 = 函数;
5.1 创建对象的第一种方式
let obj = new Object();
obj.name = "lnj";
obj.age = 33;
obj.say = function () {
console.log("hello world");
}
console.log(obj.name);
console.log(obj.age);
obj.say();
5.2 创建对象的第二种方式
let obj = {}; // let obj = new Object();
obj.name = "lnj";
obj.age = 33;
obj.say = function () {
console.log("hello world");
}
console.log(obj.name);
console.log(obj.age);
obj.say();
5.3 创建对象的第三种方式
属性名称和取值之间用冒号隔开, 属性和属性之间用逗号隔开
let obj = {
name: "lnj",
age: 33,
say: function () {
console.log("hello world");
}
};
console.log(obj.name);
console.log(obj.age);
obj.say();
函数和方法区别
- 什么是函数?
- 函数就是没有和其它的类显示的绑定在一起的, 我们就称之为函数
function demo() {
console.log("hello demo");
}
demo();
- 什么是方法?
- 方法就是显示的和其它的类绑定在一起的, 我们就称之为方法
let obj = {
name: "lnj",
test: function () {
console.log(this); //{name: "lnj", test: ƒ} 打印当前obj对象
}
obj.test();
- 函数和方法的区别
- 函数可以直接调用, 但是方法不能直接调用, 只能通过对象来调用
- 函数内部的this输出的是window, 方法内部的this输出的是当前调用的那个对象
查看1和2打印this 的结果,就知道了
- 无论是函数还是方法, 内部都有一个叫做this的东东
- this是什么? 谁调用了当前的函数或者方法, 那么当前的this就是谁
构造函数
- 什么是构造函数?
构造函数和工厂函数一样,都是用来创建对象的,构造函数本质上是工厂函数的缩写。 - 构造函数和工厂函数区别
- 构造函数的函数名首字母大写
- 构造函数只能通过new来调用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
function Person(myName,myAge){
this.myName = myName;
this.myAge = myAge;
this.say = function(){
console.log("hello word")
}
}
let obj1 = new Person('张三',33) //Person {myName: "张三", myAge: 33, say: ƒ}
let obj2 = new Person('李四',44) //Person {myName: "李四", myAge: 44, say: ƒ}
console.log(obj1)
console.log(obj2)
</script>
</head>
<body>
</body>
</html>
逻辑说明
- 当我们new Person('张三',33)的时候,系统做了什么?
1.1 会在构造函数中自动创建一个对象
let obj = new Object(); // 系统自动添加的
1.2 会自动将刚才创建的对象赋值给this
let this = obj; // 系统自动添加的
1.3 会在构造函数的最后自动添加return this;
this.say = function(){
console.log("hello word")
}
return this;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
function Person(myName,myAge){
this.myName = myName;
this.myAge = myAge;
this.say = function(){
console.log("hello word")
}
}
let obj1 = new Person('张三',33) //Person {myName: "张三", myAge: 33, say: ƒ}
let obj2 = new Person('李四',44) //Person {myName: "李四", myAge: 44, say: ƒ}
console.log(obj1)
console.log(obj2)
//由于两个对象中的say方法的实现都是一样的, 但是保存到了不同的存储空间中
console.log(obj1.say === obj2.say); // false
</script>
</head>
<body>
</body>
</html>
- 通过三个等号来判断两个函数名称, 表示判断两个函数是否都存储在同一块内存中
prototype(pro tou type)
- prototype特点
- 存储在prototype里面的方法可以被对应构造函数创建出来的所有对象共享
写法:
对象名称(大写). prototype = {}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
function Person(myName,myAge){
this.myName = myName;
this.myAge = myAge;
}
Person.prototype = {
say(){
console.log("hello word")
}
}
let obj1 = new Person('张三',33)
let obj2 = new Person('李四',44)
console.log(obj1.say === obj2.say) // true
</script>
</head>
<body>
</body>
</html>
obj1.say === obj2.say是同一个地址,所以返回true
- 除了存储方法外,还可以存储属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
function Person(myName,myAge){
this.myName = myName;
this.myAge = myAge;
}
Person.prototype = {
currentType:"人",
say(){
console.log("hello word")
}
}
let obj1 = new Person('张三',33)
let obj2 = new Person('李四',44)
console.log(obj2.currentType) // 人
console.log(obj2.currentType) // 人
</script>
</head>
<body>
</body>
</html>
currentType就是属性
- prototype中如果出现了和构造函数中同名的属性和方法,对象在访问的时候,访问到的 是构造函数中的数据
对象三角恋关系
- 每个
构造函数
中都有一个默认的属性, 叫做prototype
, prototype属性保存着一个对象, 这个对象我们称之为原型对象
- 每个"原型对象"中都有一个默认的属性, 叫做
constructor
,constructor指向当前原型对象对应的那个构造函数
- 通过构造函数创建出来的对象我们称之为"实例对象",每个"实例对象"中都有一个默认的属性, 叫做
__proto__
,__proto__
指向创建它的那个构造函数的原型对象
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
let obj1 = new Person("lnj", 34);
console.log(Person.prototype); // {constructor: ƒ}
console.log(Person.prototype.constructor);
/*
上面打印结果
Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
*/
console.log(obj1.__proto__);
/*
上面打印结果
{constructor: ƒ}
constructor: ƒ Person(myName, myAge)
__proto__: Object
*/
感谢大牛分享
帮你彻底搞懂JS中的prototype、proto与constructor(图解)
详解JavaScript中的new操作符
Function函数
- JavaScript中函数是引用类型(对象类型), 既然是对象,所以也是通过构造函数创建出来的,"所有函数"都是通过Function构造函数创建出来的对象
- JavaScript中只要是"函数"就有prototype属性,"Function函数"的prototype属性指向"Function原型对象"
- JavaScript中只要"原型对象"就有constructor属性,"Function原型对象"的constructor指向它对应的构造函数
- Person构造函数是Function构造函数的实例对象, 所以也有
__proto__
属性,Person构造函数的__proto__
属性指向"Function原型对象"
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
let obj1 = new Person("lnj", 34);
console.log(Function);
console.log(Function.prototype);
console.log(Function.prototype.constructor);
console.log(Function === Function.prototype.constructor); // true
console.log(Person.__proto__);
console.log(Person.__proto__ === Function.prototype); // true
Object函数
ƒ Object() { [native code] }
- 所有函数都是Function函数的实例,Object构造函数,就是Function构造函数的实例对象,只要是对象就有
__proto__
,
console.log(Object.__proto__); ------> ƒ () { [native code] }
console.log(Object.__proto__ == Function.prototype); ------>true
- Object的原型对象,里面的
__proto__
指向的为null
console.log(Object.prototype.__proto__); -------> null
Object函数.png
函数对象完整关系图
- Function函数是所有函数的祖先函数
- 所有构造函数都有一个prototype属性,所有prototype属性都指向自己的原型对象
- 所有构造函数都有一个constructor属性,所有constructor属性都指向自己的构造函数
- 所有函数都是对象,包括Function构造函数
- 所有对象都有一个
__proto__
属性 - 普通对象的
__proto__
属性指向创建它的那个构造函数对应的"原型对象" - 所有对象的
__proto__
属性最终都会指向"Object原型对象" - "Object原型对象"的
__proto__
属性指向NULL
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
let obj1 = new Person("lnj", 34);
//Function构造函数的原型对象的,原型对象
console.log(Function.prototype.__proto__);
//Person构造函数的原型对象的,原型对象
console.log(Person.prototype.__proto__);
//Person构造函数的原型对象的,原型对象和Function构造函数的原型对象的,原型对象,是不是指向同一个,指向的是同一个
console.log(Function.prototype.__proto__ === Person.prototype.__proto__); //true
//Object构造函数的原型对象的,原型对象和Function构造函数的原型对象的,原型对象,是不是指向同一个,指向的是同一个
console.log(Function.prototype.__proto__ === Object.prototype); //true
//Object构造函数的原型对象的,原型对象和Person构造函数的原型对象的,原型对象,是不是指向同一个,指向的是同一个
console.log(Person.prototype.__proto__ === Object.prototype); //true
函数对象完整关系图.png
注意点:为了不破坏原有的关系,在给protorype赋值的时候,需要在自定义的对象中手动的添加constructor属性,手动的添加需要指向谁。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>函数对象关系</title>
<script>
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
Person.prototype = {
currenType:'哈哈',
say:function(){
console.log('hello word')
}
}
let obj1 = new Person("lnj", 34);
console.log(Person.prototype.constructor); ------>ƒ Object() { [native code] }
</script>
</head>
<body>
</body>
</html>
上看的代码打印可以看出,Person.prototype.constructor指向的是Object函数,指向错了。破坏了原来的指向关系,手动添加一个指向,修改成下面的代码,
//原型对象
Person.prototype = {
constructor:Person,
currenType:'哈哈',
say:function(){
console.log('hello word')
}
}
再执行上面的打印结果为,
ƒ Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
对象查找方法和属性是怎么查找的---原型链
- 什么叫原型链
- 对象中
__proto__
组成的链条我们称之为原型链
- 对象查找方法和属性是怎么查找的
- 对象在查找属性和方法的时候, 会先在当前对象查找
如果当前对象中找不到想要的, 会依次去上一级原型对象中查找
如果找到Object原型对象都没有找到, 就会报错
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>原型链</title>
<script>
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
this.currentType = "构造函数中的type";
this.say = function () {
console.log("构造函数中的say");
}
}
Person.prototype = {
// 注意点: 为了不破坏原有的关系, 在给prototype赋值的时候, 需要在自定义的对象中手动的添加constructor属性, 手动的指定需要指向谁
constructor: Person,
currentType: "人",
say: function () {
console.log("hello world");
}
}
let obj1 = new Person("lnj", 34);
obj1.say(); //构造函数中的say
console.log(obj1.currentType); //构造函数中的type
// console.log(Person.prototype.constructor);
</script>
</head>
<body>
</body>
</html>
obj1.say(); 和 console.log(obj1.currentType);
如果把function Person(myName, myAge) {}这里面的say和currentType注释掉,那么就会打印prototype里面的,如果把prototype里面的注释掉,就会报错,因为prototype里再往上查找,就到Object里面的了
注意点:在给一个对象不存在的属性设置值的时候,不会去原型对象中查找,如果当前对象没有,就会给当前对象新增一个不存在的属性。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>属性注意点</title>
<script>
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
}
Person.prototype = {
constructor: Person,
currentType: "人",
say: function () {
console.log("hello world");
}
}
let obj = new Person("lnj", 34);
// console.log(obj.currentType); // "人"
// console.log(obj.__proto__.currentType); // "人"
// 注意点: 在给一个对象不存在的属性设置值的时候, 不会去原型对象中查找, 如果当前对象没有就会给当前对象新增一个不存在的属性
obj.currentType = "新设置的值";
console.log(obj.currentType); // 新设置的值
console.log(obj.__proto__.currentType); // "人"
</script>
</head>
<body>
</body>
</html>
逻辑
把上面代码 obj下面的注释解开,会发现打印的是人和人,这是从原型对象里面查找出来的,当对currentType重新进行赋值,然后再打印的话,currentType就会变成新赋的值了,而原型对象里面的值,还是原来的值。
读读大牛的思路
Javascript继承机制的设计思想
网友评论