01.原型对象
-
原型链:当前对象到Object的原型对象之间的链条
- 原型:原型对象(
prototype
,__proto__
) - 属性访问规则
- 从当前对象中查找,找不到则返回,否则进入第2步
- 在原型对象中查找,找到则返回,否则进入第3步
- 在原型对象的原型查找,找到则返回,否则继续往原型中查找,依此类推
- 直到 Object 的原型对象中查找(终点),找到则返回,否则(属性:得到的是undefined,方法:xxx is not a function)
- 原型:原型对象(
-
内置原型对象
let username="jingjing";
username.toUpperCase();
username.length; //8
- 内置原型对象 类型
- Number
- String
- Boolean
- Array
- Function
- Date
- RegExp
- … …
- 扩展内置原型对象
原则:判断不存在时才添加
- 重置原型对象:一次性扩展多个方法
避免覆盖原始属性/方法
if(!Date.prototype.formatDate){
Date.prototype.formatDate = function(){}
}
if(!Date.prototype.fromNow){
Date.prototype.fromNow = function(){}
}
// ...
// 重置原型对象
function Date(){}
Date.prototype={
formatDate(){},
fromNow(){},
// ...
...Date.prototype,
}
Object.defineProperty(Date.prototype,"constructor",{
configurable:true,
value:Date
})
02.重置原型对象
Date.prototype = {
formatDate() { },
fromNow() { },
//...
...Date.prototype,
}
// Object.assign(target,obj1,obj2,...,objN), jQuery.extends()
Object.assign(Date.prototype, {
formatDate() { },
fromNow() { },
});
// Object.assign()的使用
let jj = { username: 'jingjing', password: 123, age: 36,score:{en:85,math:70,cn:86} };
let obj1 = { gender: '女', age: 37 }
Object.assign(jj, obj1, { gender: '不详', money: 1000000, username: 'jingjing plus' });
console.log('jj=', jj);
// 利用Object.assign()实现拷贝:(浅拷贝)
let jjmm = Object.assign({},jj);
// 浅拷贝
let jjjj = {...jj};
// 深拷贝
// * 递归复制
// * JSON.stringify()/JSON.parse()
let jjBrother = JSON.parse(JSON.stringify(jj));
console.log('jjBrother',jjBrother);
深拷贝
浅拷贝
03.继承
继承概念
- 继承是面向对象中一个非常重要的特性
- 指的是子类继承父类的属性和方法
继承的好处
- 子类拥有父类所有的属性和方法(代码复用)
- 子类可以扩展自己的属性和方法(更灵活)
- 子类可以重写父类的方法
继承的方式
- 01.原型链继承法
- 核心:用父类(User)实例来充当子类(Son)原型对象
- 缺点:
- 无法继承构造函数的属性
- 创建子类实例时,无法向父类构造函数传参
- 原型对象中存在多余的属性
Son.prototype=new User;
-
02.借用构造函数法
- 核心:借父类的构造函数来增强子类实例,相当于把父类的实例属性
复制
一份给子类实例- call:
父类.call(子类实例,参数1,参数2...)
- apply:
父类.apply(子类实例,[参数1,参数2...])
- 区别:传参不同,call为多个参数,apply只能由两个参数,第二个参数为数组
- call:
- 核心:借父类的构造函数来增强子类实例,相当于把父类的实例属性
-
03.组合继承(最常用的继承方式)
-
继承属性:借用构造函数法
- 只在构造函数中定义属性
-
集成方法:原型链继承法
- 把所有的方法写入原型对象
-
缺点(原型链继承法的缺点):
- 在原型对象中生产多余的属性
- 多次执行父类构造函数
-
-
04.原型式继承:
- 核心:先创建一个临时的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时构造函数的一个新实例
- 解决了原型链继承的缺点:生成多余的属性
- 核心:先创建一个临时的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时构造函数的一个新实例
function object(o){
function F(){}
F.prototype=0;
return new F();
}
- ES5版本的原型式继承:Object.creat()
Son.prototype = Object.create(User.prototype)
04.ES6类继承
<script>
/**ES6类继承
*类:clsaa
*继承:extends
**/
class Popover{
//静态方法
//注意:ES6只支持静态方法,不支持静态属性
static show(){
console.log("hello show")
}
constructor(){
//在这里定义属性(写在实例上)
this.type="popover"
}
//在这里定义方法(写在原型上)
init(){}
drag(){}
open(){}
colse(){}
}
const pop1=new Popover();
console.log("pop1=",pop1)
//继承
class Confirm extends Popover{
//如果继承父类,并且实现自己的constructor,则必须在constructor中调用super(),只有调用super后才能使用this
constructor(){
super();
this.type="confirm"
}
init(){}
}
const conf1=new Confirm();
console.log("conf1",conf1)
</script>
05.闭包
- 概念:闭包是指 有权访问另一函数作用域中的变量的函数
- 变量访问规则:使用就近原则在作用域链查找,只能往外找,不能往里找。
- 好处:
- 可在外部操作函数内部的变量
- 让变量长期驻留内存以便下次使用
- 注意:由于闭包会携带包含它的作用域(运行环境),因此会比其他函数占用内存,过度使用闭包可能会造成性能问题
let num=10;
function test(){
let n=20;
console.log(n);
}
// test(); //20
// test(); //20
// test(); //20
function show(){
var n=20;
//定义一个函数add
function add(){
n++;
console.log(n);
}
//返回add函数,这时,在js中就形成了一个闭包,add成为闭包函数
return add;
}
// show()() //21
// show()() //21
// show()() //21
const res =show();
res(); //21
res(); //22
res(); //23
//垃圾回收机制(自动:判断变量是否还有用,自动清除没用的变量)
// *引用计数法:判断变量是否被其他引用
// *标记清除法:给变量添加标记
06.利用闭包获取点击按钮的索引值
<script>
let btns=document.querySelectorAll("button");
for(let i=0;i<btns.length;i++){
btns[i].onclick=(function(i){
function handleClick(){
console.log('i=',i)
}
return handleClick;
})(i);
}
</script>