01-JavaScript 高级进阶 第二天
1.今日目标
- 原型
- 函数定义的三种方式 了解
- 函数的原型链
- 函数和对象的原型链关系
- 函数的4种调用方式
2.定义函数的三种方式
- 函数声明
- 函数表达式
- 构造函数Function
函数声明
常规的方式
fn();//函数声明可以先调用,在声明
function fn(参数..){
console.log("这是函数声明")
return 返回值
}
函数表达式
const fn = function() {
console.log("这是函数表达式");
}
fn();//函数表达式必须先声明,再调用
构造函数Function
函数也可以看成对象
var fn1 = new Function("a1", "a2", "alert(a1+a2)");
fn1(1,2);
3.原型 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
自动帮我们在定义构造函数
的时候添加的 - 所有构造函数的实例,共享一个原型
- 原型上一般是挂载函数
图示
4.原型 proto
- 实例的
proto
属性 等于 构造函数的prototype
p1.__proto__ === Person.prototype // true
不过由于不同浏览器的兼容性问题,我们
要
使用的时候,都只会使用 构造函数的prototype
实例的 proto 只是为了方便我们开发的时候查看数据,是不会手动修改和操作它的。
5.原型的关系
所有的构造函数都是Function的实例
Array 和 Person 和 Date 等都是 Function的实例
Function 和 Object的关系
有人说
JavaScript
是作者花了7天时间写出来的产物 - 不完美
console.log(Object.prototype===Function.prototype.__proto__)
Object的顶端呢?
接近顶峰了
console.log(Object.prototype.__proto__ === null);
最终的原型链
6.作用域
变量起作用的区域
- 存在全局变量和局部变量
- 全局变量可以在任意地方使用
- 而局部变量只能用在 它所在的
花扩号的区域
思考
let num = 0;
switch (num) {
case 1:
let name = "小白"
console.log(name);
break;
case 2:
let name = "小黑"
console.log(name);
break;
default:
break;
}
学习一下谷歌浏览器的调试使用
debugger
和 谷歌浏览器的调试使用
7.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指向什么?
方法借用模式
也叫上下文模式,分为 apply 与 call
call
call方法可以调用一个函数,并且可以指定这个函数的this
指向
const RichWumon = {
name: "富婆",
say: function () {
console.log(this.name, " 我要重金求子");
}
}
const obj = {
name: "屌丝"
}
RichWumon.say(); // 富婆
RichWumon.say.call(obj); // 屌丝
call应用
- 将伪数组转成数组
let divs = document.querySelectorAll('div');
// let divs = document.body.children;
console.log(divs);
function change(nodelist) {
console.log(Object.prototype.toString.call(nodelist));
return Array.prototype.slice.call(nodelist);
}
apply
就是apply()
方法接受的是一个包含多个参数的数组。而call()
方法接受的是若干个参数的列表
可以利用apply 将 刚才的call 的代码修改一下
const RichWumon = {
name: "富婆",
say: function () {
console.log(this.name, " 我要重金求子");
}
}
const obj = {
name: "屌丝"
}
RichWumon.say(); // 富婆
RichWumon.say.apply(obj); // 屌丝
apply应用
1.简化log方法
// 简化log方法
function log() {
console.log.apply(console, arguments);
}
bind方法
bind()方法创建一个新的函数, 可以绑定新的函数的this
指向
var name = '张三';
function Fn(){
this.age = 1;
console.log(this.name + this.age);
}
Fn(); // 张三 1
// 返回值:新的函数
// 参数:新函数的this指向,当绑定了新函数的this指向后,无论使用何种调用模式,this都不会改变。
let obj = {
name:'小强',
}
const newFn = Fn.bind(obj);
newFn(); // 小强 1
8.this的指向
- 单独使用,
this
指向全局对象console.log(this); // window
函数中的
this
指向全局对象function show(){
console.log(this); // window
}
show();
- 在函数内部,
this
的指向在函数定义的时候是不能确定的,只有函数执行的时候才能确定const a = 18;
const obj = {
a: 19,
b: {
a: 20,
c: function () {
console.log(this.a); // 20
}
}
}
obj.b.c();
- 在方法中,
this
指代该调用方法的对象const obj ={
name:"小白",
say:function(){
console.log(this); // {name:"小白"}
}
}
// 箭头函数自己没有this
// 箭头函数的this是确定的,况且永远不变
// 箭头函数中的this指向 创建这个箭头函数所在对象 的上下文
let obj = {
name: 'jack',
say: function () {
return () => {
console.log(this) // obj
}
}
}
let fn = obj.say()
fn() // obj {name: "jack", say: ƒ}
let newobj = {}
newobj.fun = fn
newobj.fun() // obj {name: "jack", say: ƒ}
let rose = {
name: 'rose'
}
fn.call(rose) // obj {name: "jack", say: ƒ} 无法改变