【前端丛林】JavaScript这样服用,效果更佳(4)
前言
哈喽大家好,我是Lotzinfly,一位前端小猎人。欢迎大家来到前端丛林,在这里你将会遇到各种各样的前端猎物,我希望可以把这些前端猎物统统拿下,嚼碎了服用,并成为自己身上的骨肉。今天是我们冒险的第四天,经过三天的考验相信大家已经有了足够的经验,今天我们会遇到一个相对难对付的猎物,大家做好准备!话不多说,现在开启我们今天的前端丛林冒险之旅吧!
1. 面向对象
- 对象为无序属性的集合,其属性可以包含基本值、对象和函数
1.1 原型链
- JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
1.1.1 一切皆对象
- 对象就是一些属性的集合
- 方法也是一种属性
- 一切(引用类型)都是对象,对象是属性的集合
- 函数和数组也是对象
1.1.1.1 typeof
- 检测数据类型 typeof 返回的都是字符串
- 基本数据类型 number string boolean undefined symbol
- 引用类型 null {} [] /&$/ Date => object
console.log(typeof a); // undefined
console.log(typeof 1); // number
console.log(typeof 'xiaoming'); // string
console.log(typeof true); // boolean
console.log(typeof Symbol('a')); // symbol
console.log(typeof function () { }); //function
console.log(typeof [1, 2, 3]); //object
console.log(typeof { name: 'xiaoming' }); //object
console.log(typeof null); //object
console.log(typeof new Number(1)); //object
1.1.2 函数
- 对象是通过函数创建的
- 批量生产对象的函数 Object
- 实现私有和公有属性的封装
let obj = new Object();
obj.name='xiaoming';
obj.age = 18;
1.1.3 隐式原型
1.1.3.1 proto
- 每个对象都有一个proto属性,指向创建该对象的函数的prototype
- Object.prototype proto 指向的是 null
1.1.3.2 自定义函数的prototype
- 自定义函数的 prototype 的proto指向的就是Object.prototype
1.1.3.3 自定义函数
- 自定义函数Foo.proto指向Function.prototype
- Function的prototype和proto都指向 Function.prototype
let add = new Function('a','b','return a+b');
console.log(add(1,2));
1.1.4 instanceof
- instanceof运算符的第一个参数是一个对象,第二个参数一般是一个函数
- instanceof的判断规则是: 沿着对象的 proto 这条链来向上查找找,如果能找到函数的prototype则返回true,否则 返回false
1.2 批量创建对象
- 通过 new 来调用一个函数,这个函数就成为了构造函数,构造函数里可以对例对象的私有属性赋值
- 每个函数会有一个 prototype 属性,此原型对象上存放所有实例的公有方法
- 若new的构造函数自己返回引用值,则以自己返回的为主,否则 返回创建的实例
- create
function Person(name) {
this.name = name;
}
Person.prototype.getName = function () {
console.log(this.name);
}
let person = new Person('Lotzinfly');
person.getName();
Object.create = function (proto) {
function F() {}
F.prototype = proto;
return new F();
};
function _new(clazz, ...args) {
let _this = Object.create(clazz.prototype);
let result = clazz.call(_this, ...args);
if ((result != null && typeof result === 'object') || typeof result === 'function')
{
return result;
}
return _this;
}
- 在使用原型继承编写复杂代码之前,理解原型继承模型是至关重要的。此外,请注意代码中原型链的长度,并在必要时将其分解,以避免可能的性能问题。此外,原生原型不应该被扩展,除非它是为了与新的 JavaScript 特性兼容。
1.3 继承
class Father {
static staticFatherName = "FatherName"
static staticGetFatherName = function () {
console.log(Father.staticFatherName);
}
constructor(public name) {
this.name = name;
}
getName() {
console.log(this.name);
}
}
class Child extends Father {
static staticChildName = "ChildName"
static staticGetChildName = function () {
console.log(Child.staticChildName);
}
constructor(public name, public age) {
super(name);
this.age = age;
}
getAge() {
console.log(this.age);
}
}
let child = new Child('xiaoming', 10);
child.getName();
child.getAge();
Child.staticGetFatherName();
Child.staticGetChildName();
var _extends = (function () {
var extendStatics = function (Child, Father) {
return Object.setPrototypeOf(Child, Father);
}
return function (Child, Father) {
extendStatics(Child, Father);
function Temp() {
this.constructor = Child;
}
Temp.prototype = Father.prototype;
Child.prototype = new Temp();
};
})();
var Father = (function () {
function Father(name) { this.name = name;
}
Father.prototype.getName = function () {
console.log(this.name);
};
Father.staticFatherName = "FatherName";
Father.staticGetFatherName = function () {
console.log(Father.staticFatherName);
};
return Father;
}());
//_super父类构造函数
var Child = (function (_super) {
_extends(Child, _super);
function Child(name, age) {
_super.call(this, name);//继承父类的实例私有属性
this.age = age;
return this;
}
Child.prototype.getAge = function () {
console.log(this.age);
};
Child.staticChildName = "ChildName";
Child.staticGetChildName = function () {
console.log(Child.staticChildName);
};
return Child;
}(Father));
let child = new Child('xiaoming', 10);
console.log(child);
child.getName();
child.getAge();
Child.staticGetFatherName();
Child.staticGetChildName();
1.3.1 原型链面试题
function Foo() {
getName = function () {
console.log(1);
}
return this;
}
Foo.getName = function () {
console.log(2);
}
Foo.prototype.getName = function () {
console.log(3);
}
var getName = function () {
console.log(4);
}
function getName() {
console.log(5);
}
Foo.getName();
getName();
Foo().getName();
getName();//1
new Foo.getName();
new Foo().getName();
new new Foo().getName();
// 2 4 1 1 2 3 3
1.3.2 异步面试题
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
})
async1()
new Promise(function (resolve) {
console.log('promise1')
resolve()
}).then(function () {
console.log('promise2')
})
console.log('script end')
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
2.一张图理解原型与原型链之间的关系
结尾
好啦,这期的前端丛林大冒险先到这里啦!这期的猎物主要是原型与原型链,原型与原型链是一个不好对付猎物,大家一定要多打几遍,把它搞定,啃下来嚼烂嚼透。希望大家可以好好品尝并消化,迅速升级,接下来我们才更好地过五关斩六将,我们下期再见。拜拜!
转载自:https://juejin.cn/post/7134705497860472845