函数中运行时发生了什么
函数运行时,会自动绑定两个变量 arguments 和 this
arguments:一个实参的类数组对象
function Aoo(a, b){
console.log(arguments);
}
// 这里的a,b是形参
Aoo(1, 2, 3, 4) // 1,2,3,4
//这里的arguments就是1,2,3,4 这个就是实参
this: 函数运行时的上下文
谁调用这个方法,this就指向谁
function Aoo(){
console.log(this);
}
let obj = {
fn: Aoo,
obj2: {
fn: Aoo
}
}
Aoo(); // window 在浏览器环境下
obj.fn(); // obj
obj.obj2.fn(); // obj2
改变this指向的方法
function.call(obj,arg1,arg2,....)
function.apply(obj,[arg1,arg2,....])
function Aoo(){
console.log(this.name)
}
window.name = 'window'
Aoo();// window
let obj = {
name: 'objName'
}
Aoo.call(obj) // objName
Aoo.apply(obj) // objName
// 如果后面带参数的话
function Boo(arg1,arg2){
this.a = arg1;
this.b = arg2;
console.log(this);
}
Boo('1', '2');//window.a === '1' windwo.b === '2'
let obj2 = {
name: 'obj2'
}
Boo.call(obj2, '1', '2') //{name: "obj2", a: "1", b: "2"}
Boo.apply(obj2, ['1', '2']) //{name: "obj2", a: "1", b: "2"}
new 一个对象时发生了什么
首先,我们需要知道JS的原型链
function Person(name){
this.name = name;
}
// 我们将Person这个函数的公共方法写在prototype上,后面通过Person函数new出来的实例都可以使用这些方法
Person.prototype.introduct = function(){
console.log(`Hello, my name is ${this.name}`)
}
let p = new Person('jack');
let p2 = new Person('rose');
p.introduct();//Hello, my name is jack
p2.introduct();//Hello, my name is rose
// 为什么可以实现呢
// 因为p.__proto__ === Person.prototype,当p实例上找不到introduct这个方法时,就会顺着__proto__去寻找原型对象上是否存在这个方法
了解原型链后,探究一下new一个对象时发生了什么
function Person(name){
this.name = name;
}
let p = new Person('rose')// {name: "rose", __proto__: Object}
//1.创建一个空对象
let obj = {};
//2.将这个空对象的__proto__指向构造函数的prototype
obj.__proto__ = Person.prototype;
//3.将构造函数的this指向这个空对象
//4.运行构造函数
Person.call(obj, name)
//5.返回这个对象
return obj;
// 经过这5步,我们就可以产生一个由构造函数new出来的实例
如何实现继承
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.introduct = function(){
console.log(`my name is ${this.name}, my age is ${this.age}`);
}
function Student(hobby){
this.hobby = hobby;
}
Student.prototype.showHobby = function(){
console.log(`my hobby is ${this.hobby}`);
}
// 如果Student是Person的一个子类,我们需要如何实现继承
实现继承,我们就应该实现student的实例可以使用Person函数的属性和方法
let s = new Student('Tom', 22, 'javascript');
// 如果只是这样写,是无法在student对象加上name,age属性的
// 因此,我们可以改写Student方法
function Student(name, age, hobby){
//我们再执行student构造函数的具体方法前先执行Person的构造方法
Person.call(this, name, age);
this.hobby = hobby;
}
// 结合new的原理,我们可以知道
/*
1. 先生成一个空对象 let obj = {}
2. obj.__proto__ = Student.prototype
3. 绑定obj到this上
4. obj执行Person的构造函数
5. obj执行Student的构造函数
6. 返回obj
s: {name: 'Tom', age: 22, hobby: 'javascript'}
注: 到这里,我们student实例s上有了Person的属性,但是没有protoype上的方法
*/
回头来看
s实例之所以不可以使用Person上的方法,是因为Student函数没有继承.
Student.prototype是一个object,这个实例应该继承Person原型上的方法
所以,Student.prototype.__proto__ = Person.prototype
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.introduct = function(){
console.log(`my name is ${this.name}, my age is ${this.age}`);
}
function Student(name,age,hobby){
Person.call(this,name,age)
this.hobby = hobby;
}
Student.prototype.__proto__ = Person.prototype;
Student.prototype.showHobby = function(){
console.log(`my hobby is ${this.hobby}`);
}
let ss = new Student('yvan', 22, 'node.js');
console.log(ss);
ss.introduct();// my name is yvan, my age is 22
ss.showHobby();// my hobby is node.js