面向对象
1、对象、类、实例
JS 本身是基于面向对象思想设计出来的一门编程语言,当我们给予JS进行程序设计的时候,也应该按照面向对象的想法去开发或者理解。
对象,一种泛指
类:对象的一部分
实例:某个类中的具体事物
2、内置类
【数据类型】
-
Number 、 String、 Boolean 、 (Symbol、BigInt)
-
Object、Array、RegExp、Date…
-
Function
【每一个元素对象都有一个自己所属的类】
-
HTMLHtmlElement / HTMLBodyElement / HTMLDivElement
-
HTMLElement XMLElement HTMLDocument
dir(document)
【元素/节点/样式/集合】
Document.getElemrntsByTagName("*")
Window.getComputedStyle(document.body)
3、 自定义类
自定义类,创建自定义类的实例
function Func(x,y){
let total = x + y;
this.result = total;
this.say = function(){}
return 10 // 返回基本类型,new时还是他的实例
}
// 普通函数执行
let f = Func(10,20); // undefined
result // 30
/* 构造函数执行
* 执行时,new一个函数,此时函数称为自定义类,一般返回值被称为当前一个类的实例,特殊情况
*/
let f = new Func(10,20)
// f => Func {result: 30}
let f1 = new Func
let f2 = new Func
f1.say === f2.say // false
// 验证某个属性是否为当前对象的属性
// + in 验证私有公有属性都可以
// + hasOwnProperty 验证私有属性
// instanceof 检测当前实例是不是属于某个类
分析构造函数执行做了哪些事情
三句话玩转面向对象
1、每一个函数类型(构造函数(类)),天生具备一个属性"prototype原型",属性值是一个对象,存储当前类的公共属性和方法。供实例来调用。
2、在原型对象上有一个内置的属性"constructor"构造函数,存储的值是当前函数本身,所以把类称为构造函数
3、每一个对象都天生具备一个属性,"__proto__隐式原型/原型链属性", 属性值指向自己所属类的原型对象(实例的.__proto__ = 所属类的.prototype)
函数类型
- 普通函数
- 构造函数(类)
- 所有内置类都是一个函数 Object、Function..
> typeof Number , typeof Object. 'function'
对象类型
- prototype/__proto__
- 函数也是对象
- 类的实例也是对象(排除基本数据类型值的特殊性)
- 万物皆对象
// 举例
// Object.create([Object])
创建一个空对象,并且把[Object]对象作为新空对象的原指向
// x.__proto__ = [Object]
创建一个没有原型/原型链的对象 不是任何的实例
// Object.create(null)
// Object.create 不兼容低端浏览器
// 我们写的这个方法不支持null的处理
Object.create = function create(prototype){
if(prototype ===null || typeof prototype==='object'){
throw new TypeError(`Object prototype may only be an Object or null: ${prototype}`)
}
// 创建一个类,创建这个类的实例,实例.__proto__ = 类.prototype 我们让类prototype等于传递的prototype
function Temp(){}
Temp.prototype = prototype;
return new Temp
}
// 实现一个自定义new
function Dog(name){
this.name = name;
}
Dog.prototype.brak = function (){
console.log('wangwang')
}
Dog.prototype.sayName = function (name){
console.log('my name is'+name)
}
/*
* Func要操作这个类(最后创建这个类的实例)
* args存储未来传递给Func类的实参
*/
function _new(Func,...args){
// 1、创建一个Func的实例对象,(实例的.__proto__应该指向类的.prototype)
// 因为在ie浏览器中,禁止我们使用__proto__(IE没有暴露这个方法,防止我们去改变原型指向),
/*
let obj = {};
obj.__proto__ = Func.prototype;
*/
let obj = Object.create(Func.prototype)
// 2、把Func当普通函数执行,(让方法中的this指向创建的实例)
let result = Func.call(obj,...args);
// 3、分析函数执行的返回值,没有返回值或者返回的是原始类型的值,默认都返回创建的实例,否则以函数自身返回的为主
if(result !==null && /^(object|function)$/.test(typeof result)){
return result
}
return obj
}
let sanmao = _new(Dog,'三毛')
sanmao.brak() // 'wangwang'
sanmao.sayName('sanmao') // 'my name is sanmao'
console.log(sanmao instanceof Func) // true
4、 This 的五种情况
/*
* THIS:执行主体(谁把他执行的),所以THIS和执行上下文不是一个东西
*
* 如何区分执行主体:和函数在哪执行和创建没有必然的关系
* 1. 函数执行,看函数前看是否有“点”,有“点”它前面是谁THIS就是谁,没有“点”THIS就是window(非严格模式)/undefined(严格模式)
* + 自执行函数中的THIS一般都是window/undefined
* + 回调函数中的THIS一般也是window/undefined(除非某个函数内部给回调函数做了特殊的处理,这样回调函数中的THIS有自己的特殊情况)
* 2. 给当前元素的某个事件行为绑定方法,当事件行为触发,方法中的THIS是当前操作的元素(特殊:IE6~8中基于DOM2事件绑定attachEvent,方法中的this不是元素)
* 3. 箭头函数中(私有块级上下文)没有自己的THIS,所用到的THIS都是其上级上下文中的THIS(也就是没有初始化THIS这一步)
* 4. 构造函数中的THIS一般是当前类的实例
* 5. 基于call/apply/bind可以强制改变THIS
*/
// console.log(this); //=>window
/* (function () {
console.log(this); //=>window
})(); */
/* setTimeout(function () {
console.log(this); //=>window
}, 0); */
/* let obj = {
fn: (function () {
// this => window
return function () {
console.log(this);
}
})() //把自执行函数执行的返回值赋值给fn属性(自执行函数只有给fn赋值的时候执行一次,后期执行obj.fn()执行的是返回的小函数)
};
obj.fn(); //this=>obj
let fn = obj.fn;
fn(); //this=>window */
/* var fullName = 'language';
var obj = {
fullName: 'javascript',
prop: {
getFullName: function () {
return this.fullName;
}
}
};
console.log(obj.prop.getFullName());
// this -> obj.prop
// obj.prop.fullName => undefined
var test = obj.prop.getFullName;
console.log(test());
// this -> window
// window.fullName => 'language' */
/* var name = 'window';
var Tom = {
name: "Tom",
show: function () {
// this -> window
console.log(this.name); //=>'window'
},
wait: function () {
// this -> Tom
var fun = this.show;
fun();
}
};
Tom.wait(); */
/* window.val = 1;
var json = {
val: 10,
dbl: function () {
this.val *= 2; // this.val=this.val*2
}
}
json.dbl();
// this -> json
// json.val=json.val*2=20
var dbl = json.dbl;
dbl();
// this -> window
// window.val=window.val*2=2
json.dbl.call(window);
// this -> window
// window.val=window.val*2=4
alert(window.val + json.val); //=>"24" */
/* (function () {
// this -> window
var val = 1;
var json = {
val: 10,
dbl: function () {
val *= 2; // val=val*2
// val是一个变量,让自执行函数中的私有变量val=2
}
};
json.dbl();
alert(json.val + val); //=>"12"
})(); */
/* var num = 10;
var obj = {
num: 20
};
obj.fn = (function (num) {
this.num = num * 3;
num++;
return function (n) {
this.num += n;
num++;
console.log(num);
}
})(obj.num);
var fn = obj.fn;
fn(5);
obj.fn(10);
console.log(num, obj.num); */
5、实现一个new操作符
// Func要操作的这个类(最后要创建这个类的实例)
// ARGS存储未来传递给Func类的实参
function _new(Func, ...args) {
// 1.创建一个FUNC的实例对象(实例.__proto__=>类.prototype)
// 在IE浏览器中,禁止我们使用__proto__(也可以理解为IE并没有提供给我们__proto__这个属性,防止我们去改变原型指向)
/* let obj = {};
obj.__proto__ = Func.prototype; */
let obj = Object.create(Func.prototype);
// 2.把FUNC当做普通函数执行(让方法中的THIS指向创建的实例)
let result = Func.call(obj, ...args);
// 3.分析函数执行的返回值(没有返回值或者返回的是原始值类型则默认都返回创建的实例,否则以函数自身返回的为主)
if (result !== null && /^(object|function)$/.test(typeof result)) {
return result;
}
return obj;
}
let sanmao = _new(Dog, '三毛');
sanmao.bark(); //=>"wangwang"
sanmao.sayName(); //=>"my name is 三毛"
console.log(sanmao instanceof Dog); //=>true