网站首页 > 技术文章 正文
开头
笔记视频内容源自B站JavaScript从入门到放弃 第十二章 面向对象编程,笔记为自行整理复习使用,欢迎一同学习交流,转载请通知原作者
一、原型、原型链
1.1、什么是面向对象?
面向对象编程是目前主流的的一个编程的模式,它将我们真实世界各种复杂的关系抽象成了一个个的对象,然后由这些对象的分工合作完成真实世界的模拟。每一个对象都有其功能中心,即完成的任务(方法,属性)。因此面向对象编程(OOP)具有灵活、代码可复用、高度模块化等特点。
1.对象是单个实物的抽象
2.对象是一个容器,封装了对应的属性和方法,属性是对象的状态,方法是对象的行为(完成的任务)
1.2、构造函数实例化对象
生成一个对象通常需要一个模板(表示一类实物的共同特征),让对象生成
类(class)就是对象的模板,但是js不是基于类的,而是基于构造函数(constructor)和原型链(prototype),我们来看一段代码:
<body>
<script>
function Dog(name, age) {
//name和age就是当前实例化对象的属性
this.name = name;
this.age = age;
}
var dog1 = new Dog("阿黄", 10);
</script>
</body>
这个Dog()是构造函数,为了与普通函数区别,构造函数的名字的第一个字母通常都大写
构造函数的特点:
- 函数体内使用this关键字,代表了所要生成的对象实例
- 生成对象必须通过new关键字实例化
如果没有new关键字,Dog函数为普通函数没有返回值,结果就是undefined
<body>
<script>
function Dog(name, age) {
//name和age就是当前实例化对象的属性
this.name = name;
this.age = age;
}
// var dog1 = new Dog("阿黄", 10);
var d = Dog("阿黄", 10);
console.log(d);
</script>
</body>
使用严格模式报错会进一步扩大:
<body>
<script>
function Dog(name, age) {
'use strict'
this.name = name;
this.age = age;
}
var d = Dog("阿黄", 10);
console.log(d);
</script>
</body>
1.3、instanceof用法
instanceof表示当前对象是否是它的类的实例,如果是返回true,不是返回false
<body>
<script>
function Dog(name){
if(!(this instanceof Dog)){
//this指向了window,外部没有使用关键字new
return new Dog(name)
}
//this指向当前实例,外部使用了关键字new
this.name = name;
}
var d1 = Dog('阿黄')
console.log(d1);
</script>
</body>
上面的代码利用instanceof关键字来判断,如果是作为普通函数进来,this的指向为window而不是Dog,返回一个new过后的构造函数,如果是则赋值其name属性
1.4、new命令原理
当我们使用new命令时发生了什么呢?我们使用一段代码来研究一下:
<body>
<script>
function Person(name){
this.name = name
}
var p1 = new Person();
console.log(p1);
console.log(p1.__proto__ === Person.prototype) //true
console.log(Person.prototype);
</script>
</body>
首先new关键字构造函数后:
- 创建一个空对象,作为将要返回的对象实例
- 将空对象的原型对象指向了构造函数的prototype属性对象
3.将这个实例对象的值赋值给函数内部的this关键字
? 4.指向构造函数体内的代码
1.5、constructor属性
constructor是在每个对象创建时都会自动的拥有的一个构造函数属性
<body>
<script>
function Person(name){
this.name = name
}
var p1 = new Person('chen');
console.log(p1);
console.log(p1.constructor);
console.log(p1.constructor === Person);
console.log(Person.prototype);
</script>
</body>
constructor继承自原型对象,其中指向了构造函数的引用,所以p1.constructor === Person应该为true
使用构造函数创建对象的好处在于,能够共享内部属性和方法:
<body>
<script>
function Person(name) {
this.name = name;
this.sayName = function () {
console.log(this.name);
};
}
var p1 = new Person('Tom');
var p2 = new Person('Jack');
console.log(p1,p2);
</script>
</body>
就像p1和p2,它们都各自用有自己的name属性。但同样的也有弊端:每个实例调用的时候方法都要重新创建,存在冗余,想要解决这类方法要使用原型对象(prototype)来解决
1.6、原型对象介绍
先看代码:
<body>
<script>
function Foo() {}
Foo.prototype.name = "chen";
Foo.prototype.showName = function () {
console.log("fchen");
};
var f1 = new Foo();
var f2 = new Foo();
console.log(f1.name);
console.log(f2.name);
f1.showName();
f2.showName();
</script>
</body>
原型对象:Foo.prototype
实例对象:f1就是实例对象,实例对象可以构造多个,每一个原型对象中都有一个__proto__,每个实例对象都有一个constructor属性,这个constructor通过继承关系继承来的,它指向了当前的构造函数Foo
构造函数:用来初始化新创建对象的函数,Foo就是构造函数,自动给构造函数赋予一个属性prototype,该属性指向了实例对象的原型对象(__proto__)
1.7、原型链
<body>
<script>
function Foo(){};
var f1 = new Foo();
</script>
</body>
以上面的代码结合图示来分析一下Foo构造函数的原型链:
Foo的实例对象f1,它的原型对象f1.__proto__指向了Foo的prototype属性,f1的constructor属性间接继承于Foo,如果将Foo.prototype也当作一个实例化的对象,同样的他也会有__proto__与constructor属性,Foo.prototype.__proto__指向了Object.prototype,``Foo.prototype.constructor**直接继承**于Foo`,如图所示:
控制台与图示一致,f1.__proto__ === Foo.prototype
再深入下去,将Foo当成一个实例对象,它的__proto__又将指向哪一个呢:
Object实例对象的__proto__为null
把Foo和Object再当成一个实例,它们也有对应的constructor
__proto__也同理:
函数也是一个对象,任何函数我们可以看作是Function所new出来的对象,如果我们把Foo当作对象它同样的有__proto__和constructor属性
再再深究下去Funtion实例对象也有其__proto__和constructor属性
Foo里面的constructor是继承而来的,继承的当前构造函数的原型
这就是原型链,是不是很绕(我也晕晕的),研究的就是原型对象
1.8、prototype属性的作用
js的继承就是通过prototype来进行的
什么是js的继承机制?
<body>
<script>
function Foo() {}
var f1 = new Foo();
Foo.prototype.name = "chen";
console.log(f1.name);
</script>
</body>
看结果:
可以看到,name属性并不在f1上,而是通过继承挂载在f1的原型对象(__proto__)上
<body>
<script>
function Foo() {}
var f1 = new Foo();
var f2 = new Foo();
Foo.prototype.name = "chen";
console.log(f1.name);
console.log(f2.name);
Foo.prototype.name = "chen2";
console.log(f1.name);
console.log(f2.name);
</script>
</body>
可以看到两个实例都会被修改
JS继承机制,通过原型对象(__proto__)实现继承。原型对象的作用,就是定义了所有的实例对象共享的属性和方法
读取属性和方法的规则:js引擎会先寻找对象本身的属性和方法,如果找不到就到它的原型对象去找,如果还是找不到,就到原型的原型去找,如果直到最顶层的Object.prototype还是找不到,就会返回undefined 如果对象和它的原型,都定制了同名的属性,那么优先读取对象自身的属性,这也叫覆盖
<body>
<script>
function Foo() {}
var f1 = new Foo();
var f2 = new Foo();
Object.prototype.showName = function(){
console.log(24);
}
f1.showName()
var arr = [12,3,4]
arr.showName()
</script>
</body>
所有的对象的尽头都是Object
接下来我们编写一段代码,让我们自己的构造函数拥有数组的部分属性和方法:
<body>
<script>
function MyArray() {}
MyArray.prototype = Array.prototype;
var arr = new MyArray();
console.log(arr);
arr.push(1,2,3)
console.log(arr);
</script>
</body>
但是上面的代码同时也改变了他的constructor,修改成了数组的constructor,怎么样能不改变构造函数的指向呢
要添加这一句:
MyArray.prototype.constructor = MyArray;
我们打印一下arr.constructor
总结:一旦我们修改构造函数的原型对象,为防止引用出现问题,同时也要修改原型对象的constructor属性
constructor属性表示原型对象和构造函数之间的关联关系
1.9、总结
function Foo(){};
var f1 = new Foo();
构造函数:Foo
实例对象:f1
原型对象:Foo.prototype
1.原型对象和实例对象的关系
console.log(Foo.prototype === f1.__proto__);
2.原型对象和构造函数的关系
console.log(Foo.prototype.constructor === Foo);
3.实例对象和构造函数
间接关系是实例对象可以继承远程对象的constructor属性
console.log(f1.constructor === Foo);
Foo.protptype={};
console.log(Foo.prototype === f1.__proto__);
console.log(Foo.prototype.constructor === Foo);
所以,代码的顺序很重要
猜你喜欢
- 2024-11-10 这样理解 JS 原型链,通透 js原型链的理解
- 2024-11-10 JavaScript-原型链 javascript 原型,原型链 ? 有什么特点?
- 2024-11-10 javascript原型链 js原型链的用处
- 2024-11-10 js 原型/原型链/构造函数/实例/继承
- 2024-11-10 【JavaScript 高级】深入了解原型链
- 2024-11-10 快速读懂JavaScript中的原型链 js的原型和原型链是什么
- 2024-11-10 你可能不太理解的JavaScript - 原型与原型链
- 2024-11-10 我在jacascript中学习到的那些原型链,你知道吗?
- 2024-11-10 JavaScript中的原型prototype和__proto__的区别及原型链概念
- 2024-11-10 面试问题分享 - 5:解释一下 原型、构造函、实例、原型链 之间的关系
- 标签列表
-
- content-disposition (47)
- nth-child (56)
- math.pow (44)
- 原型和原型链 (63)
- canvas mdn (36)
- css @media (49)
- promise mdn (39)
- readasdataurl (52)
- if-modified-since (49)
- css ::after (50)
- border-image-slice (40)
- flex mdn (37)
- .join (41)
- function.apply (60)
- input type number (64)
- weakmap (62)
- js arguments (45)
- js delete方法 (61)
- blob type (44)
- math.max.apply (51)
- js (44)
- firefox 3 (47)
- cssbox-sizing (52)
- js删除 (49)
- js for continue (56)
- 最新留言
-