业界最顶尖的技术大咖/最权威的实战分享/最前沿的行业资讯/尽在腾讯课堂Coding学院
长按二维码关注Coding学院
来源:Coding学院(ID:ke_coding)
01存在的问题一切皆对象js是面向对象语言,在js中,一切都是对象,甚至连函数都是对象(Function 是JS自带的函数对象,typeof值是function)。这意味着可以把函数像其它值一样传递,从这个角度来看甚至比java更加面向对象。 js中几乎所有变量都可以当做对象来使用,(除了null和undefined)1. 对象中的属性 访问属性 有两种方式来访问对象的属性,点操作符或者中括号操作符。 varpeople ={name:'annie'} 删除属性删除属性的唯一方法是使用delete操作符; 设置属性为undefined或者null并不能真正的删除属性,而仅仅是移除了属性和值的关联。 2. 原型在ES6之前,JavaScript中不包含传统的类继承模型,不直接支持class和extends关键字,而是使用prototype原型继承的方式。 (1)原型对象在JavaScript 中,每当定义一个对象(函数)时候,对象中都会包含一些预定义的属性。其中函数对象的一个属性就是原型对象 prototype(注意普通对象没有prototype,但有__proto__属性)。原型对象主要的作用就是用来实现继承的。通过给person.prototype设置了一个函数对象的属性,所有person实例就继承了这个属性。 (2)原型链JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype。以上面的例子为例:同样,person.prototype对象的__proto__属性指向创建它的函数对象(Object)的prototypeObject.prototype对象也有__proto__属性,但它比较特殊,为null把所有这些__proto__串起来的直到Object.prototype.__proto__为null的链就叫做叫做原型链。(3)属性查找原型链继承带来的性能问题 查找机制:当查找一个对象的属性时,Js会向上遍历原型链,直到找到给定名称的属性为止。 到查找到达原型链的顶部,也就是Object.prototype,但是仍然没有找到指定的属性,就会返回undefined。 性能问题:如果一个属性在原型链的上端,则对于查找时间将带来不利影响。特别的,试图获取一个不存在的属性将会遍历整个原型链。并且,当使用for in循环遍历对象的属性时,原型链上的所有属性都将被访问。 (4) 性能提升hasOwnProperty函数hasOwnProperty是继承自Object.prototype的方法,可以判断一个对象是否包含自定义属性而不是原型链上的属性 for in循环同样在查找对象属性时遍历原型链上的所有属性。可以结合hasOwnProperty进行过滤(5) monkey patching js有一个很奇怪的设计,就是不限制扩展Object.prototype或者其他内置类型的原型对象,但这样做会破坏封装,是错误的使用理念。 02函数
函数在JavaScript中也是一种对象,这意味着可以把函数像其它值一样传递。 1. 函数的声明方式(1)函数声明这样的声明方式使函数会在执行前被解析,因此它存在于当前上下文的任意一个地方,即使在函数定义体的上面被调用也是对的。 (2)函数表达式函数赋值表达式:把一个匿名的函数赋值给变量func。但是由于赋值语句只在运行时执行,因此在相应代码执行之前,func的值缺省为undefined。 2.thisJs中,this在不同的情况下有五种不同的指向 (1)全局范围内,它将会指向全局对象 (2)函数调用情况下,也会指向全局对象。 (3)方法调用,指向该方法对应的对象 陷阱: 对象的方法内部的函数中的this指向全局(4)构造函数,指向新创建的对象 (5)apply/call,当使用Function.prototype上的call或者apply方法时,函数内的this将会被显式设置为函数调用的第一个参数。 3. 构造函数(1)js中,通过new关键字方式调用的函数都被认为是构造函数。 (2)这个新创建的对象的 prototype被指向到构造函数的prototype。 (3)如果被调用的函数没有显式的return表达式,则隐式的会返回this对象,也就是新创建的对象。显式的return表达式将会影响返回结果,但仅限于返回的是一个对象。(4)构造的另一种实现方式工厂模式 如果new被遗漏了,则函数不会返回新创建的对象。 为了避免这种情况,不使用new关键字,构造函数必须显式的返回一个值。为了创建新对象,我们可以创建一个工厂方法,并且在方法内构造一个新对象。缺点: 工厂模式会占用更多的内存,因为新创建的对象不能共享原型上的方法。 为了实现继承,工厂方法需要从另外一个对象拷贝所有属性,或者把一个对象作为新创建对象的原型。 放弃原型链仅仅是因为防止遗漏new带来的问题,这似乎和语言本身的思想相违背。 4. 作用域(1)JavaScript 中只存在两种作用域: 全局作用域 函数作用域 尽管 支持一对花括号创建的代码段,但是并不支持块级作用域; (2)隐式的全局变量 不使用var声明变量将会导致隐式的全局变量产生。 (3)局部变量 Js中局部变量只可能通过两种方式声明,一个是作为函数参数,另一个是通过var关键字声明。 (4)Js会提升变量声明。 这意味着var表达式和function声明都将会被提升到当前作用域的顶部。但是var表达式只是定义被提升,此时值缺省为undefined!赋值操作还是运行时。 5. 闭包闭包机制的源头是js是函数作用域,没有块级作用域,函数内部可访问外部,外部不可访问内部。 闭包机制的目的有两个:一个是使得外部可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。 函数是js中唯一拥有自身作用域的结构,因此闭包的创建依赖于函数。可以把闭包简单理解成"定义在一个函数内部的函数"。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。 我们看一个经典的例子上面的代码不会输出数字0到9,而是会输出数字10十次。当console.log被调用的时候,匿名函数中发现没有i,就会沿着作用域链向上找,找到了外层for循环的i变量并保持对外部变量i的引用,此时for循环已经结束,i的值被修改成了10.归根结底的原因就是因为由于不存在块级作用域,因此内部没有保持住 i。 为了得到想要的结果,我们以闭包的方式进行改造,需要在每次循环中创建变量i的拷贝。03类型
1. 类型的比较== JavaScript是弱类型语言,这就意味着,等于操作符会为了比较两个值而进行强制类型转换。 ==是不好的编程习惯: a.它的复杂转换规则,会导致难以跟踪的问题。 b.强制类型转换也会带来性能消耗, === 严格等于操作符不会进行强制类型转换 2.Typeoftypeof操作符或许是JavaScript中最大的设计缺陷,因为几乎不可能从它们那里得到想要的结果,大多数情况下都返回"object"。 为了检测一个对象的类型,应使用Object.prototype.toString方法; 此外,instanceof操作符用来比较两个操作数的构造函数。只有在比较自定义的对象时才有意义。如果用来比较内置类型,将会一样用处不大。 04ES6中的类es6引入类(模板)的概念,class关键字来定义类,extends关键字来实现继承。 但这本质上只是提供更方便开发的语法糖,它的绝大部分功能,es5都可以做到。 业界最顶尖的技术大咖/最权威的实战分享/最前沿的行业资讯/尽在腾讯课堂Coding学院 长按二维码关注Coding学院 |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|