面向对象
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