js 中 this 原型

1、对象属性

分类

  • 数据属性
  • 存储属性

相关方法

Object.defineProperty(obj, 属性, {
// 数据属性 
	configuration: false,
	enumerable: false,
	writable: false,
	value: xx,
// 存储属性
	configuration: false,
	enumerable: false,
	set function(val){ 属性 = val },
	get function(){ return obj[属性] }
// 通过 let obj = { name: 'zhangsna' }; obj.age = 12; 方式增加属性,这些属性的属性描述符都是 true (configuration、enumerable、writable)
// 对象的原型里面的 constructor 属性的默认属性描述符(enumerable 为 false)(configuration、writable 为 true)
}) 
Object.getOwnPropertyDescriptor(obj,属性名字) // 对象某一属性的属性描述符
Object.getOwnPropertyDescriptors(obj) // 获取对象的所有属性的属性描述符
Object.preventExtensions(obj) // 禁止属性里面增加属性
Object.freeze(obj) // 禁止对象一级属性的修改 (把对象的所有一级属性的属性描述符 writable = false)
Object.seal(obj) // 禁止对象一级属性的删除 (把对象的所有一级属性的属性描述符 configuration= false)

2、THIS

类型

- new
	function Father() {
	 this.name = 'zhangsan'; // 约等于 obj.name = 'zhangsan'
	}
	let obj = new Father(); // obj 中的 this 指向 obj
- call、bind、apply // 显示改变 this 指向; 若不指定 this 则this 为全局作用域中的 this
- obj.fn() // fn 中的 this 指向调用者 obj
- 全局作用域中的默认 this
	浏览器环境中为 window
	node 环境为 {}
- 内置函数中的默认 this
	setTimeOut() 全局作用域中的 this
	监听时间、点击事件中的 this 指向对应的 dom 结点
- 箭头函数中的 this 指向定义箭头函数时的外部作用域中的 this

重写 call bind apply

Array.prototype.slice.call(arguments)
Function.prototype.mycall = function(newThis,...arg) {
    newThis = newThis ?? window;
	let fn = this;
	newThis.fn = fn;
	let result = newThis.fn(...arg);
	delete newThis.fn
	return result
}
Function.prototype.myApply= function(newThis,argArr) {
    newThis = newThis ?? window;
    argArr = argArr || [];
	let fn = this;
	newThis.fn = fn;
	let result = newThis.fn(...argArr );
	delete newThis.fn
	return result
}
Function.prototype.mycall = function(newThis,...argA) {
	let fn = this;
	newThis = newThis ?? window;
	function proxyFn(...argB) {
		newThis.fn = fn;
		let result = newThis.fn(...[...argA, ...argB])
		delete newThis.fn;
		return result
	}
	return proxyFn;
}

3、原型

介绍

Function Father(name,arr) {
	this.name = name;
	this.arr = arr;
	this.commonString = 'commonString';
	this.commonArr = ['commonArr'];
	this.commonFunction = () => {};
}
let father1 = new Father();
// 此时 father1.__proto__ ==== Father.prototype;
// Father 的 prototype 类似于 {constructor: Father}

图一

分类

-  对象的原型 (隐式原型)
	- 获取方法 	
		obj.__proto__ // 浏览器的方法
		Object.getPrototypeOf(obj)
	- 对象的隐式原型是其构造函数的显示原型
	    let obj = {};
	    obj.__proto__ === Object.prototype // true
	    Object.prototype.__proto__ === null
-  函数的原型 (显示原型、隐式原型)
		fn.prototype // 显示原型
		fn.__proto__ // 隐式原型 浏览器的方法

原型链

查找对象属性的路径:对象本身(该对象的构造函数身上) 》对象构造函数的原型身上 》…》null
在这里插入图片描述

其他

let o = {};
let obj = Object.create(o) 
//此时 obj.__proto__ ==== o; 类似于 Object.setPrototype(obj, o);

4、创建对象模式

  • 工厂模式
function Factory(name, age) {
 return {
 	name,
 	age,
 	commonArr: [1,2];
 	commonFn() {
 	}
 }
}
const p1 = Factory();
const p2 = Factory();
// 缺点
- p1、p2 都是对象类型,不能变成想要的类型。构造函数可以解决这一问题。
- 每创建一个实例公共方法都会再创建一次,造成存储浪费。原型可以解决这一问题。
  • 构造函数模式
function Father(name, age) {
 return {
 	name,
 	age,
 	commonArr: [1,2];
 	commonFn() {
 	}
 }
}
const p1 = new Father();
const p2 = new Father();
// 创建出来的实例都有自己的类型为 Fahther 而不是通用的 Object 
// 依然存在内存浪费问题
  • 原型链模式
function Father(name, age) {
 return {
 	name,
 	age,

 }
}
Father.prototype = {
	commonArr: [1,2];
 	commonFn() {
 	}
}
Object.defineProperty(Fahter.prototype, 'constructor', {
	configuration: true,
	enumerable: false,
	writeable: true,
	value: Father,
})
// 把公共方法放到原型中解决了内存浪费问题。

5、继承

  • 原型链继承(子构造函数的原型为父构造函数的实例)
    在这里插入图片描述
    Student 实例查找属性的方式 Student 的构造函数 》 Person 的构造函数 (Student 的构造函数) 》Person 的原型 》 … 》null
    缺点:不能实现多类继承;不能向父构造函数传参;当 Student 实例 s1 中没有某属性 xx 时,给该 s1.xx 赋值,若 xx 为引用数据类型并且父构造函数中有该属性,此时修改 xx 会影响到其他 Student 的实例(个人觉得第三点不是原型继承特有的)。
  • 组合时继承:构造函数继承: 在Son构造函数内部执行:Father.call(this,参数) + 原型链继承
    ① 父构造函数至少调用两次: 子类原型时候使用+构造函数继承时候用
    ②子类实例会拥有两份父类的属性:子类实例自己里面的+子类原型对象中的
  • 寄生式继承
    在这里插入图片描述
    缺点: 类似于工厂函数。
  • 最佳选择: 寄生的 Object.create + 构造函数 new + 组合式子构造函数中调用父构造函数
    在这里插入图片描述在这里插入图片描述

class

const outerJMethod = () => {
  console.log('外部箭头函数',this)
}
function outerFMethod () {
  console.log('外部function定义的函数', this)
}

class MyClass {
  static myStaticProp = 42;
  instanceProp = '实例属性';
  constructor() {
    this.cInstanceProp = '构造函数中的实例属性'
    // 所有实例共享同一片空间,但箭头函数中的 this 指向定义时候的外部作用域,普通函数中 this 指向调用者
    this.cOuterJMethod = outerJMethod;
    this.cOuterFMethod = outerFMethod;

    this.cInstanceJMethod = ()=>{
      console.log('构造函数中的实例箭头方法', this); // 构造函数中的 this 是 new 出来的新对象(实例),箭头函数中的 this 指向定义是的外部作用域也就是实例
    }
    this.cInstanceFMethod = function() {
      console.log('构造函数中的实例箭头方法', this); // 构造函数中的 this 是 new 出来的新对象(实例),箭头函数中的 this 指向定义是的外部作用域也就是实例
    }
  };
  // 实例方法
  instanceJProp = ()=>{
    console.log('实例箭头方法', this)
  };
  // 类的原型方法
  instanceFProp() {
    console.log('实例function方法', this)
  };
}
const p1 = new MyClass();
const p2 = new MyClass();

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
  • 类的属性方法、实例的属性方法、类原型的属性方法;
  • 类中用 static 修饰的属性或方法只能用类本身调用,且都是类的属性或方法,类的属性或方法只能是 static 修饰的或者通过增加对象属性的方法例如 类名.xx = xxx 增加或修改;
  • 类中没有修饰符修饰的属性都是实例属性,没有修饰符修饰的方法中箭头函数是实例方法而非箭头函数构造的则是类的原型方法;
  • 类中构造器用 this.xx = xxx 的都是实例的属性或方法,构造器中的 this 指向的是新的实例。

小技巧

-
	Reflect.set(obj,(a = 1));
	// 相当于
	a=1;
	Reflect.set(obj, 1);
- 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值