构造函数、原型和原型链(极其重点)
对象的属性和方法被称为成员
首字母要大写
function Star(name, age) {
// 实例成员
this.name = name
this.age = age
this.sing = () => {
console.log("sing");
}
}
let ldh = new Star('ldh', 18)
ldh.sing() // 访问实例成员的方法
Star.sex = 'man' // 添加静态成员的唯一方法
console.log(Star.sex);// 访问静态成员的唯一方法
构造函数的this
每个构造函数的this都是指向实例对象,这里 就是指向 a 这个实例对象。
function Fn(){ this.user = "wakanda forever"; } var a = new Fn(); console.log(a.user); // wakanda forever
概括原型内容
不同的构造函数对应不同prototype对象
同一个构造函数生成的实例对象 的
__proto__
指向相同的prototype不同的构造函数生成的实例对象 的
__proto__
指向不同的prototype
构造函数和原型 prototype
》启用原型原因:
构造函数的实例对象的方法都是相同的
但每个实例都会生成相同的方法,造成资源浪费。
可以用prototype原型优化,节约空间
》解决方案 要记忆
构造函数可通过原型 让所有实例共享方法,节约空间
我们将一些不变的方法直接定义在prototype中,可以让所有的实例都能共享了
(实例对象通过
__proto__
指向prototype对象)(不同构造函数之间的prototype对象是不同的)
// 比较后是false console.log(Star1.prototype === Star.prototype);// false
》JavaScript 规定 重点
每一个构造函数都有一个prototype属性,prototype属性指向 prototype 对象
(prototype是一个对象)
prototype对象的成员,会被构造函数的实例对象所共享。
// JavaScript v8浏览器环境中 function Star{} let ss = new Star() console.log(ss);
添加成员到prototype的方式
function Star(name, age) { this.name = name this.age = age } let ldh = new Star('ldh', 18) console.log(ldh); // 下面这个 Star.prototype.sing = () => { console.log("sing"); }
ldh.sing() // 标准使用方式
注意 :别一不小心把prototype覆盖掉了
Star.prototype = {} // 否则要手动加入constructor
对象原型__ proto
__
》知识点
实例对象都会有一个
__proto__
指向 对应的构造函数的prototype原型对象之所以我们对象可以使用构造函数的prototype 成员,就是因为
__proto__
的存在》证明
function Star(name, age) { this.name = name this.age = age } let ldh = new Star('ldh', 18) Star.prototype.sing = () => { console.log("sing"); } console.log(ldh.__proto__); // Star { sing: [Function] } console.log(Star.prototype);// Star { sing: [Function] } console.log(Star.prototype === ldh.__proto__); //true 指向地址相同
》使用方法
// 标准使用方式 实例名.xxx成员 如:ldh.sing() // 即可 // 禁止下面的使用方式,因为不符合标准 ldh.__proto__.sing()
原型查找规则
先查找构造函数本身定义的
其次是通过
__proto__
在prototype对象上查找
constructor 构造函数
》介绍
实例原型(
__proto__
)和构造函数原型对象(prototype)里面都有constructor,指向构造函数本身。
原型链
Star构造函数 :你写的
ldh 实例对象 :你创建的
Star原型对象:默认的
object原型对象:默认的父类
object构造函数:默认的父类
null :到顶层了
查找规则
1> 2 >3
继承
介绍 ES6之前不存在extends,原型链又只能是默认的
模拟继承: 构造函数 +原型对象
用call和apply改变构造函数的this,指向父类构造函数即可,构成新的原型链
fn.call(需要指向的名,数据1,数据2,…)
》知识点
改变函数的this指向
》应用场景
非箭头函数 的this 默认指向了window ,因此为了改变这种指向
引入了call
》使用
var a = { name:"ldh" } function name(params) { console.log(this) // node就是指向global 浏览器就是指向window } name() // 默认,node环境就是指向globa,浏览器就是指向window name.call(a) // 指向了a
参数 作用 需要指向的名 重新改变this的指向,并填入要被指向的名 数据1 携带参数 其他数据 携带参数
fn.apply(需要指向的名,数据集合)
介绍
和call类似,就是传输的参数不一样
var a = {
name: "ldh"
}
function name(a, b, ...c) {
console.log(this)
console.log('a=' + a, 'b=' + b, ...c)
}
name.call(a, 5, 6, 7, 8, 9, 70) // 解开的
name.apply(a, [1, 2, 3]) // 集合的
继承案例
建议做一下断点测试
// 父类
function B(a) {
this.a = a
console.log(a)
}
// 子类
function A(b) {
B.call(this, b) // 指向B
this.b = b
}
A(12) // 打印 12
ES6中的构造函数
需要一些面向对象的编程基础才容易理解 如JAVA
class A {
// 负责接受参数
constructor(x, y) {
this.x = x
this.y = y
}
login() {
console.log("logining!");
console.log(this.x,this.y);
}
}
class B extends A{
}
let ldh = new B(12, 10)
console.log(ldh);
ldh.login()
class A {
// 负责接受参数
constructor(x, y) {
this.x = x
this.y = y
}
login() {
console.log("logining!");
console.log(this.x,this.y);
}
}
class B extends A{
}
let ldh = new B(12, 10)
console.log(ldh);
ldh.login()