一、复习
- 所有的 this.xxx的属性都是当前实例的私有属性
- 约定的规范,原型上的方法中的this保证是当前类的实例
- 一般我们会把方法类的属性放到原型上
【选项卡过渡写法】
function Tab(id) {
//所有的 this.xxx的属性都是当前实例的私有属性
//一般我们会把方法类的属性,放到原型上
let ele = document.getElementById(id);
let buttons = ele.getElementsByTagName('button')
let divs = ele.getElementsByTagName('div')
this.divs = divs;
for(var i=0;i<buttons.length;i++){
buttons[i].n = i;
buttons[i].onclick = function(){
for(var j=0;j<divs.length;j++){
divs[j].style.display = 'none';
}
//console.log(this.n);
divs[this.n].style.display = 'block';
}
}
}
Tab.prototype.hideDivs = function(){
}
Tab.prototype.init = function(index){
for(var i=0;i<this.divs.length;i++){
this.divs[i].style.display = 'none';
}
this.divs[index].style.display = 'block'
}
let tab1 = new Tab('box')
tab1.init(1)
- 作用域:变量提升
私有作用域:形参赋值 和声明过的
上级作用域:只看函数是在哪个作用域形成的 - 作用域链:变量的查找机制
- 原型:创建类的时候会用到,当一个对象去调用一个属性的时候
- 数字或者字符串能不能调用pop?
数字是Number类的实例,pop是在Array.prototype上存在,调用不到 - let p1 = new Person();//不需要实参的时候,可以省略()
function Tab(id) {
// 所有的 this.xxx的属性都是当前实例的私有属性
// 一般 我们会把方法类的属性 放到原型上
// this.qqq = function () {}
// this --->
let ele = document.getElementById(id)
let buttons = ele.getElementsByTagName('button')
let divs = ele.getElementsByTagName('div')
this.divs = divs
for (var i = 0; i < buttons.length; i++) {
buttons[i].n = i;
let _this = this;
buttons[i].onclick = function () {
_this.hideDivs(this.n)
/* for (var j = 0; j < divs.length; j++) {
// 让所有的div消失
divs[j].style.display = 'none'
}
// this --> 某一个button
// console.log(this.n) 对应就是点击的button的索引
divs[this.n].style.display = 'block' */
}
}
}
Tab.prototype.hideDivs = function (n) {
// 约定的规范: 原型上的方法中的this保证是 当前类的实例;
// this -- > tab1
for (var i = 0; i < this.divs.length; i++) {
this.divs[i].style.display = 'none'
}
this.divs[n].style.display = 'block'
}
Tab.prototype.qqq = function (index) {
// 让索引未 index的div显示,其他隐藏
// this ---> tab1
console.log(this.divs)
this.hideDivs(index)
}
let tab1 = new Tab('box')
tab1.qqq(1) // qqq执行的时候 里边的this 是 tab1;
console.log(tab1)
let tab2 = new Tab('box2')
tab2.qqq(2)
二、new
- 代码 :p = new Person()
- 执行过程:
先开一个作用域,然后开辟一个堆内存,把this指向 这个堆内存,
形参赋值 &变量提升-->代码执行; - 返回值:不是引用的话,就默认返回this
call
- 代码:fn.call(xxx,a,b,c)
- 参数:
xxx:表示把fn函数中的this指向xxx;
a,b,c:从第二个参数以后的当作实参给fn的形参传递
【手写实现new】
//基础版
function myNew(C, name) {
let obj = {};
obj.__proto__ = C.prototype
// Person中的this指向这个堆
let res = C.call(obj, name) // 需要判断C->Person返回的是是类型
// res是call执行的返回结果;call的返回结果就是C的返回结果
// res 就是 C的执行结果
if (typeof res == 'object') {
return res
} else {
return obj
}
}
function Person(name) {
this.name = name
}
let p1 = new Person("小明")
let p2 = myNew(Person, '小明')
let p3 = myNew(Person, '小明')
p1.__proto__ === Person.prototype
p2.__proto__ === Person.prototype
function Person(name, age, sex) {
this.name = name
this.age = age;
this.sex = sex;
}
let p1 = new Person("小康", 12, 1)
let p2 = myNew(Person, "小康", 12, 1)
function myNew(C, ...args) {
let obj = {};
obj.__proto__ = C.prototype;
let res = C.call(obj, ...args)
let res = C.apply(obj, args)
return typeof res == 'object' ? res : obj
}
三、instanceof
- 代码:A instanceof B
- 作用:从A到基类的prototype这条原型链上有没有B.prototype存在
- 返回值:ture 或者false
//原理讲解
var ary = [];
// console.log(ary instanceof Array) // true
// 从ary 到 Object类的prototype 这条链上 有没有Array.prototype
function myInstance(a, b) {
// 从 a到Object类的prototype 这条链上有没有b.prototype
// a.__proto__....__proto__ === b.prototype
// a.__proto__ 是否是b.prototype
// 若不是 a.__proto__.__proto__ 是否是b.prototype
// 若还不是a.__proto__.__proto__.__proto__ 是否是b.prototype
// 若有一层__proto__ == b.prototype 应该返回true
// 若a.__proto__.。。。.__proto__ === null; 应该false
let temp = a.__proto__;
while (temp && temp !== b.prototype) {
// temp存在 并且 temp不是b.prototype
// 证明temp不是null;而且temp不等于b的原型
// 下一步就是 看看a.__proto__.__proto__
// temp.__proto__
temp = temp.__proto__
}
// return temp ? true : false
// 什么情况能跳出while
// temp === null;
// temp === b.prototype
if (temp == null) {
return false
} else {
return true
}
}
console.log(myInstance(ary, Array)) // true
console.log(myInstance({}, Object)) // true
console.log(myInstance(ary, Number)) // false
【手写实现instanceof】
function instance_of(L, R) {
//L 表示左表达式,R 表示右表达式
L = L.__proto__; // 取 L 的隐式原型
while (true) {
if (L === null) return false;
if (R.prototype === L)
// 这里重点:当 O 严格等于 L 时,返回 true
return true;
L = L.__proto__;
}
}
\