JS进阶(四)面向对象

本文深入讲解JavaScript中的面向对象编程,包括对象、类、实例的概念,内置类与自定义类的区别,以及构造函数、原型和实例之间的关系。同时,探讨了this关键字在不同执行上下文中的表现,以及如何实现自定义new操作符。
摘要由CSDN通过智能技术生成

面向对象

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值