农历2019即将过去,趁着年前几天上班事情少,整理了一下javascript的基础知识,在此给你们作下分享,喜欢的大佬们能够给个小赞。本文在github也作了收录。javascript
本人github: github.com/Michael-lzg前端
每一个构造函数(constructor)都有一个原型对象(prototype), 原型对象都包含一个指向构造函数的指针, 而实例(instance)都包含一个指向原型对象的内部指针.
咱们先来看一个例子java
function Person(name, age, job) { this.name = name this.age = age this.job = job this.sayName = function() { alert(this.name) } } var person1 = new Person('Zaxlct', 28, 'Engineer') var person2 = new Person('Mick', 23, 'Doctor')
上面的例子中 person1 和 person2 都是 Person 的实例。这两个实例都有一个 constructor (构造函数)属性,该属性(是一个指针)指向 Person。 即:webpack
console.log(person1.constructor == Person) //true console.log(person2.constructor == Person) //true
每一个构造函数都有一个 prototype 属性,指向调用该构造函数而建立的实例的原型,也就是这个例子中的 person1 和 person2 的原型。git
function Person() {} Person.prototype.name = 'Zaxlct' Person.prototype.age = 28 Person.prototype.job = 'Engineer' Person.prototype.sayName = function() { alert(this.name) } var person1 = new Person() person1.sayName() // 'Zaxlct' var person2 = new Person() person2.sayName() // 'Zaxlct' console.log(person1.sayName == person2.sayName) //true
这是每个 JavaScript 对象(除了 null )都具备的一个属性,叫proto,这个属性会指向该对象的原型。es6
function Person() {} var person1 = new Person() console.log(person1.__proto__ === Person.prototype) // true
每一个原型都有一个 constructor 属性指向关联的构造函数github
function Person() {} var person1 = new Person() console.log(Person === Person.prototype.constructor) // true console.log(person1.__proto__ === Person.prototype) // true
当读取实例的属性时,若是找不到,就会查找与对象关联的原型中的属性,若是还查不到,就去找原型的原型,一直找到最顶层为止。web
function Person() {} Person.prototype.name = 'Kevin' var person = new Person() person.name = 'Daisy' console.log(person.name) // Daisy delete person.name console.log(person.name) // Kevin
在这个例子中,咱们给实例对象 person 添加了 name 属性,当咱们打印 person.name 的时候,结果天然为 Daisy。面试
可是当咱们删除了 person 的 name 属性时,读取 person.name,从 person 对象中找不到 name 属性就会从 person 的原型也就是 person.proto ,也就是 Person.prototype 中查找,幸运的是咱们找到了 name 属性,结果为 Kevin。
语法:Object.create(proto, [propertiesObject])
方法建立一个新对象,使用现有的对象来提供新建立的对象的 proto。
// new Object() 方式建立 var a = { rep: 'apple' } var b = new Object(a) console.log(b) // {rep: "apple"} console.log(b.__proto__) // {} console.log(b.rep) // {rep: "apple"} // Object.create() 方式建立 var a = { rep: 'apple' } var b = Object.create(a) console.log(b) // {} console.log(b.__proto__) // {rep: "apple"} console.log(b.rep) // {rep: "apple"}
经典面试题
var obj1 = { name: 'one' } obj2 = Object.create(obj1) obj2.name = 'two' console.log(obj1.name) //one var obj1 = { prop: { name: 'one' } } obj2 = Object.create(obj1) obj2.prop.name = 'two' console.log(obj1.prop.name) //two var obj1 = { list: ['one', 'one', 'one'] } obj2 = Object.create(obj1) obj2.list[0] = 'two' console.log(obj1.list[0]) //two
在函数内部定义的变量和函数若是不对外提供接口,那么外部将没法访问到,也就是变为私有变量和私有函数。
function Obj() { var a = 0 //私有变量 var fn = function() { //私有函数 } } var o = new Obj() console.log(o.a) //undefined console.log(o.fn) //undefined
当定义一个函数后经过 “.”为其添加的属性和函数,经过对象自己仍然能够访问获得,可是其实例却访问不到,这样的变量和函数分别被称为静态变量和静态函数。
function Obj() {} Obj.a = 0 //静态变量 Obj.fn = function() { //静态函数 } console.log(Obj.a) //0 console.log(typeof Obj.fn) //function var o = new Obj() console.log(o.a) //undefined console.log(typeof o.fn) //undefined
在面向对象编程中除了一些库函数咱们仍是但愿在对象定义的时候同时定义一些属性和方法,实例化后能够访问,JavaScript也能作到这样。
function Obj(){ this.a=[]; //实例变量 this.fn=function(){ //实例方法 } } console.log(typeof Obj.a); //undefined console.log(typeof Obj.fn); //undefined var o=new Obj(); console.log(typeof o.a); //object console.log(typeof o.fn); //function
题目以下
function Foo() { getName = function() { alert(1) } return this } Foo.getName = function() { alert(2) } Foo.prototype.getName = function() { alert(3) } var getName = function() { alert(4) } function getName() { alert(5) } //请写出如下输出结果: Foo.getName() getName() Foo().getName() getName() new Foo.getName() new Foo().getName() new new Foo().getName()
解读:首先定义了一个叫 Foo 的函数,以后为 Foo 建立了一个叫 getName 的静态属性存储了一个匿名函数,以后为 Foo 的原型对象新建立了一个叫 getName 的匿名函数。以后又经过函数变量表达式建立了一个 getName 的函数,最后再声明一个叫 getName 函数。
先来剧透一下答案,再来看看具体分析
//答案: Foo.getName() //2 getName() //4 Foo().getName() //1 getName() //1 new Foo.getName() //2 new Foo().getName() //3 new new Foo().getName() //3
1.第一问:Foo.getName 天然是访问 Foo 函数上存储的静态属性,天然是 2
2.第二问,直接调用 getName 函数。既然是直接调用那么就是访问当前上文做用域内的叫 getName 的函数,因此跟 1 2 3 都没什么关系。可是此处有两个坑,一是变量声明提高,二是函数表达式。
关于函数变量提示,此处省略一万字。。。。题中代码最终执行时的是
function Foo() { getName = function() { alert(1) } return this } var getName //只提高变量声明 function getName() { alert(5) } //提高函数声明,覆盖var的声明 Foo.getName = function() { alert(2) } Foo.prototype.getName = function() { alert(3) } getName = function() { alert(4) } //最终的赋值再次覆盖function getName声明 getName() //最终输出4
3.第三问的 Foo().getName(); 先执行了 Foo 函数,而后调用 Foo 函数的返回值对象的 getName 属性函数。这里 Foo 函数的返回值是 this,this 指向 window 对象。因此第三问至关于执行 window.getName()。 然而这里 Foo 函数将此变量的值赋值为function(){alert(1)}
。
4.第四问直接调用 getName 函数,至关于 window.getName(),答案和前面同样。
5.后面三问都是考察 js 的运算符优先级问题。
总结前端性能优化的方法
几种常见的JS递归算法
搭建一个vue-cli的移动端H5开发模板
封装一个toast和dialog组件并发布到npm
从零开始构建一个webpack项目
总结几个webpack打包优化的方法
一文读尽前端路由、后端路由、单页面应用、多页面应用
关于几个移动端软键盘的坑及其解决方案
浅谈JavaScript的防抖与节流