一般函数与构造函数
函数还是之前的函数,惟一的区别就是首字母大写
// 构造函数
function Foo(m, n) {
let ret = m + n;
this.m = m;
this.n = n;
return ret;
}
// 一般函数
function foo(m, n) {
let ret = m + n;
this.m = m;
this.n = n;
return ret;
}
一般函数
- 失常调用,不须要 new 关键字
- 执行过程还是按着堆栈执行 + 作用域链查找机制
// 一般函数调用
let ret = Foo(10, 20);
console.log(ret);
构造函数
- 应用 new 关键字调用
- 执行 new 操作时,浏览器会创立一个空间示意空对象与 this 进行关联,this 指向是新创建的实例
- 函数体内如果没有 return 或者说 return 的是根本数据类型,默认返回对象实例;函数体内如果返回援用类型,那么就以本人返回为主
- 函数此时叫做类,返回的后果叫对象实例
// 构造函数执行
let res = new Foo(20, 20);
console.log(res);
new 操作符
- 失常状况下应用 new 实现对象实例创立,如果以后类不须要传递参数,则能够不加括号运行
- new Foo, 未加小括号阐明 FOO 不须要传参,称之为无参列表
- new Foo 与 new Foo() 的优先级不同,前者为 19,后者为 20
- 每一次 new 都会将函数从新执行,生成一个新的执行上下文,创立一个新的实例对象,因而两个实例对象不一样
重写 new 办法
new 做了什么
- 创立实例对象
- 执行构造函数,将 this 指向实例对象
- 解决返回值
模仿 new 实现
function Person(name) {this.name = name;}
Person.prototype.slogan = function () {console.log("前端界最帅的人");
};
Person.prototype.sayName = function () {console.log(` 我的名字是 ${this.name}`);
};
// let p1 = new Person('zce')
// p1.slogan()
// p1.sayName()
function _new(Ctor, ...params) {
//01 创立实例对象
// let obj = {}
// obj.__proto__ = Ctor.prototype
let obj = Object.create(Ctor.prototype);
//02 调用构造函数,扭转 this 指向
let ret = Ctor.call(obj, ...params);
//03 解决返回后果
if (ret !== null && /^(object|function)$/.test(typeof ret)) {return ret;}
return obj;
}
let p1 = _new(Person, "zce");
p1.slogan();
p1.sayName();
console.log(p1 instanceof Person);
原型及原型链
名词阐明
prototype 属性
- 每一个函数(除箭头函数)数据类型,都自带一个 prototype 属性,指向原型对象(Function 除外)
- 每个原型对象自带一个 constructor 属性,指向以后构造函数自身
-
函数数据类型
- 一般函数、箭头函数、生成器函数
- 构造函数(自定义类)
- 内置函数(内置构造函数)
proto 属性
- 每一个对象数据类型,都自带一个 proto 属性,(隐式原型)
- 该属性的值指向所属类的原型对象 prototype
-
对象数据类型
- 一般对象、数组对象、正则对象、日期对象
- prototype 原型对象
- 实例对象
- 函数也是对象
Object 类
- 所有对象都是 Object 内置类的实例
- Object 也是一个函数,同样具备 prototype 属性,指向本人的原型对象
- 它的原型也是一个对象,因而具备 proto 属性
- Object 原型对象的 proto 指向 Null(外部设计)
原型链查找机制
- 首先找本人公有的属性,公有中存在就是公有的
- 公有中不存在,则默认基于 proto 找所属类的原型对象
- 如果类的原型上没有,则基于原型对象的 proto 持续向上查找,直到找到 Object.prototype 为止
示例代码
function Foo() {
this.m = 10;
this.n = 24;
this.getM = function () {console.log(this.m);
};
}
Foo.prototype.getM = function () {console.log(this.m);
};
Foo.prototype.getN = function () {console.log(this.n);
};
let foo1 = new Foo();
let foo2 = new Foo();
console.log(foo1.getM === foo2.getM);
console.log(foo1.getN === foo2.getN);
console.log(foo1.__proto__.getN === Foo.prototype.getN);
console.log(foo1.__proto__.getM === foo2.getM);
console.log(foo1.getM === Foo.prototype.getM);
console.log(foo1.constructor);
console.log(Foo.prototype.__proto__.constructor);
foo1.getM();
foo1.__proto__.getM();
foo2.getN();
Foo.prototype.getN();
Function 与 Object
函数多种角色
-
函数
- 一般函数调用(堆栈执行作用域)
- 构造函数实例化(原型及原型链)
-
对象
- 键值对
- 三种角色之间没有必然的分割,然而最外围的函数就是函数
语录
- Function 是一等公民,在 JS 中存在多种角色,一般函数、构造函数、对象
- 每一个对象都存在 proto 属性,指向所属类的原型对象(隐式原型,原型链属性)
- 每一个函数都存在 prototype 属性,指向它的原型对象
- 所有函数都是 Function 内置类的实例,且 Function 自身也是一个函数
- 所有对象都是 Object 的实例,且 Object 自身也是一个函数
- Function 与 Object 是二大并行的基类,尽管最终查找落脚点都是 Object 身上
- Function.prototype 原型对象是一个匿名函数,尽管它是一个函数,然而它的解决机制和原型对象是一样的,它的 proto 属性指向所属类的原型对象,也就是 Object.prototype
不具备 prototype 属性
- Function.prototype 不具备,是一个匿名函数
- 对象中应用 ES6 语法定义函数
const obj = {say(){}}
- 箭头函数
- 不具备 prototype 属性的函数是不能执行 new 操作的