原型 prototype -重点
原型上存放函数
- 解决了同一个
say浪费 内存的问题 - 解决了污染全局变量的问题
function createStudent(name, age) {
this.name = name;
this.age = age;
}
// 将刚才的全局函数say 直接挂载到 构造函数的原型上 即可
// prototype 是个对象 每一个构造函数都会内置有的. 我们称之为原型
createStudent.prototype.say = function () {
console.log(this.name);
}
const obj = new createStudent("悟能", 83);
const obj1 = new createStudent("悟能1", 84);
console.log(obj.say === obj1.say); // true
原型解释
- 原型的单词是
prototype, 原型的这个名字是行业内共同认可的名字。 - 原型本质是一个对象,理解为
JavaScript自动帮我们添加的,只要是构造函数,系统会默认的为构造函数关联一个对象,这个对象就称为构造函数的原型,写在原型中的成员,可以被构造函数所创建的实例调用 - 原型是
JavaScript自动帮我们在定义构造函数的时候添加的 - 所有构造函数的实例,共享一个原型
- 原型上一般是挂载函数
3.原型 proto
- Javascript 规定,每一个(构造)函数都有一个
prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。这也就意味着,我们可以把所有对象实例需要共享的属性和方法直接定义在prototype对象上,以便让同一类型的对象共享方法或其它成员
4.原型的关系
构造函数、实例、原型三者之间的关系
构造函数:构造函数就是一个函数,配合new可以新建对象。
实例:通过构造函数实例化出来的对象我们把它叫做构造函数的实例。一个构造函数可以有很多实例。
原型:每一个构造函数都有一个属性prototype,函数的prototype属性值就是原型。通过构造函数创建出来的实例能够直接使用原型上的属性和方法。
5.原型链
1概念
任何一个对象,都有原型对象,原型对象本身又是一个对象,所以原型对象也有自己的原型对象,这样一环扣一环就形成了一个链式结构,我们把这个链式结构称为:原型链。 总结:Object.prototype是原型链的尽头,Object.prototype的原型是null。
属性查找原则
如果是获取操作
- 会先在自身上查找,如果没有
- 则根据
__proto__对应的原型去找,如果没有 - 一直找到
Object.prototype,如果没有,那就找不到从而报错
6.es5 原型链继承
利用代码的能力实现 面向对象的特性 封装 和 继承
初体验
- 子类strudent 继承了父类 Person的属性
// 父类
function Person(name, height) {
this.name = name;
this.height = height;
}
Person.prototype.say = function () {
console.log(this.name);
console.log(this.height);
}
// 子类
function Student(grade, name, height) {
// 借用了父类的构造函数,完成对自己的赋值
Person.call(this, name, height)
this.grade = grade;
}
// 赋值了父类原型上的所有的 属性和方法
Student.prototype = Person.prototype;
// 修改之类的指向
Student.prototype.constructor = Student;
// 创建子类的实例
const stu = new Student("一年", "周星星", 170);
stu.say();
7.作用域及作用域链
let所创建的变量的作用域是从创建这个let变量到它所在的结构的}结束
作用域:变量起作用的区域,也就是说:变量定义后,可以在哪个范围内使用该变量。
var num = 11;//全局变量
function fn(){
var num1 = 22;//局部变量,只有方法体内可以使用
console.log(num); // 函数内部可以使用函数外部声明的变量,全局变量在任何地方都能访问到
console.log(num1);
}
console.log(num);
在js里只有全局作用域和函数作用域。
函数作用域是在函数定义的时候作用域就确定下来了,和函数在哪调用无关。
-
我们只关注函数的定义位置而不关注函数的调用位置
- 定义函数,函数的作用域就确定了
- 以后函数做为参数,不影响函数的作用域
var num = 123;
function f1() {
console.log(num); // 123
}
function f2(){
var num = 456;
f1();
}
f2();//打印啥?
作用域链
作用域链:只要是函数,就会形成一个作用域,如果这个函数被嵌套在其他函数中,那么外部函数也有自己的作用域,这个一直往上到全局环境,就形成了一个作用域链。
变量的搜索原则:
- 从当前作用域开始查找是否声明了该变量,如果存在,那么就直接返回这个变量的值。
- 如果不存在,就会往上一层作用域查询,如果存在,就返回。
- 如果不存在,一直查询到全局作用域,如果存在,就返回。如果在全局中也没有找到该变量会报错
8.this与函数的四种调用模式
根据函数内部this的指向不同,可以将函数的调用模式分成4种
- 函数调用模式
- 方法调用模式
- 构造函数调用模式
- 上下文调用模式(借用方法模式)
函数调用模式
如果一个函数不是一个对象的属性时,就是被当做一个函数来进行调用的。此时this指向了window
function fn(){
console.log(this);// 指向window
}
fn();
方法调用模式
当一个函数被保存为对象的一个属性时,我们称之为一个方法。当一个方法被调用时,this被绑定到当前对象
const obj = {
sayHi:function(){
console.log(this);//在方法调用模式中,this指向调用当前方法的对象。
}
}
obj.sayHi();
构造函数调用模式
如果函数是通过new关键字进行调用的,此时this被绑定到创建出来的新对象上。
function Person(){
console.log(this);
}
Person();//this指向什么?
var p = new Person();//this指向什么?