----------------------------常见的面试问题:数组去重,总结几个,下去敲敲--------------------
最好要用IIEF。
1)双层循环加splice方法
2)indexof去重
3)includes去重
4)利用空对象替换覆盖法
5)利用递归法
。。。
--------------------------------------------------开始今天的内容----------------------------------------
一:原型与原型链
prototype原型:
1)每一个函数都有很多的属性和方法,有一个prototype属性,它对应的value是一个对象,这个对象我们叫做原型对象。
2)原型对象上放了很多的属性和方法
3)每一个原型对象上必定有一个constructor。constructor也是一个属性名,它的value值是当前这个函数(类)本身。
4)每一个对象上都有一个属性__proto__,对应的value是创建这个对象的类的原型对象。
5)这个原型对象里面也有一个__proto__对应的是Object对应的原型对象(基类)。因为object是最顶层的类,也叫基类。
6)所以Object.prototype.__proto__指向它自己。由于指向自己没有任何意义,所以说它的默认值就是null
原型链
如果找一个属性,先在自己内部(私有的)找。
如果有,就使用,不再向后找。
如果没有,就沿着__proto__,找类原型对象上的属性,一直向上找,直到找到Object.prototype为止。
----------------------------------来俩小测题---------------看看有没有被原型链给绕进去
function Func(){this.name = "张" } let obj1 = new Func(); let obj2 = new Func();Func.prototype.say = function(){console.log("say...") }
测试题 console.log(obj1.say === obj2.say) 、、obj1和obj2指向同一块原型对象,里面的方法一致 console.log(Func.prototype.say === obj1.say) 、、obj1里面没有say,去它的原型对象中找, 它的原型对象指向创建这个对象的类的原型对象 console.log(obj1.__proto__.say === Func.prototype.say) 、、obj1的原型对象指向创建这个对象的类的原型对象 console.log(obj1.__proto__ === Func.prototype) 、、obj1的原型对象指向创建这个对象的类的原型对象 console.log(obj1.name === obj2.name) 、、两个对象都没有传参,都是undefined,返回true console.log(obj1 instanceof Func) 、、func也是一个对象 console.log(obj1 instanceof Object) 、、类型一致
测试2
var arr1 = new Array("a","b","c") var arr2 = new Array("d","e","f")
console.log(Array.prototype === arr1.__proto__) 、、Array属于内置对象,内置类,构造函数,arr1的原型对象对应创建它的类的原型对象 console.log(Array.prototype.push === arr1.push) 、、arr1上没有push,会去它的原型对象上去找,所以与它的原型对象上的push相对应 console.log(arr1 === arr2) 、、arr1与arr2是两块堆,不一样,false console.log(arr1 instanceof Array) 。。 console.log(arr1 instanceof Object) 。。 console.dir(arr1.__proto__)//原型对象 console.dir(arr1.__proto__.__proto__)//原型对象指向object指向的原型对象,基类 console.dir(arr1.__proto__.__proto__.__proto__)//null
二.难搞的this
关于this的问题,this出现的几个地方
1)在监听器中,this表示事件源
btn事件源,on 前缀,click事件类型
2)在非严格模式下。this出现在普通函数中,表示window,在严格模式下,表示undefined
严格模式:use strict
3)this出现在一个对象的方法中,表示当前这个对象
4)this出现在构造函数中,表示指向一个新的对象
5)在全局变量下,this表示window
this中的精髓:方法中的this指向不确定,谁调用了方法this,这个this就指向谁
一系列的练习题:
(1)
function Func(){this.a = 1;this.b = 2;this.say = function(){console.log(this.a)} } Func.prototype.say = function(){console.log(this.b) } Func.prototype.jump = function(){// 谁调用了jump方法,jump方法中的this就是谁console.log(this.a+this.b) } let wc = new Func(); wc.jump(); // 3
(2)
function Func(){this.a = 1;this.b = 2;this.say = function(){console.log(this.a)} } Func.prototype.say = function(){// 谁调用了say这个方法,那么this就是谁// wc.__proto__ console.log(this.b) } Func.prototype.jump = function(){console.log(this.a+this.b) } let wc = new Func(); // 明确指出调用原型对象上的方法 // wc.__proto__ 它调用了say方法,那么这个方法中的this就是wc.__proto__ wc.__proto__.say(); // undefined
(3)
function Func(){this.a = 1;this.b = 2;this.say = function(){console.log(this.a)} } Func.prototype.say = function(){console.log(this.b) } Func.prototype.jump = function(){// 此时this表示wc.__proto__console.log(this.a) // undefinedconsole.log(this.b) // undefinedconsole.log(this.a+this.b) // NaN } let wc = new Func(); wc.__proto__.jump(); // NaN
三.关于匿名函数的一些问题
1)var f =function(){},这是把一个匿名函数赋值给了f。
对于上面的匿名函数表达式,可以给这个匿名函数,指定函数名g。。
var f = function g(){console.log("haha...")}
f()
g()//会打印出, g is not defined
//前面我们讲过,不能通过函数表达式的函数名来调用,所以只能通过f(),不可以g().
2)那怎么使用匿名函数名?那就在它自己的函数体中使用
举个例子:
var f = function g(){console.log(g) // g是函数名,可以在函数体中使用g(); // 可以通过g()调用这个函数,但是没有出口会死循环g = 1; // 把基本数据类型赋值给g没有作用g = []; // 引用数据类型赋值给g也没有作用g = {};g = function(){console.log("xixi...")}console.log(g) }f()
总结匿名函数名注意事项:
1)匿名函数名可以在函数体中使用
2)可以直接调用,但是没有出口会死循环
3)不能重新赋值,基本数据类型和引用数据类型都不可以
4)综上所述:对于函数表达式来说,它可以有函数名,它可以在内部调用,不能再外部通过函数名调用!
-----------------------------------------来俩例子练练---------------------------
(1)
var a = function abc(num) {abc = num;console.log(num) console.log(abc) console.log(typeof abc) }a(1)
(2)
var a = function abc(num) {abc = num;return 1;}a(1)console.log(abc())
四.关于this的练习请找下篇面试题总结this(有点多)。。