javascript学习心得[通俗易懂] 您所在的位置:网站首页 node学习心得 javascript学习心得[通俗易懂]

javascript学习心得[通俗易懂]

2023-03-24 01:32| 来源: 网络整理| 查看: 265

javascript学习心得[通俗易懂] 思创斯忠实用户-ss • 2023年3月20日 06:00 • Java

javascript学习心得[通俗易懂]不论你是想学各种前端框架还是nodejs,都需要深入理解javascript的工作原理以及特性,只有这样才能以不变应万变。最近看了一些js的教学视频与NC的《JS的高级程序设计》这本书,在这里总结一下js的一些特性,以防自己忘记,也可以方便各位朋友学习与交流。

大家好,我是你的好朋友思创斯。今天说一说javascript学习心得[通俗易懂],希望您对编程的造诣更进一步.

javascript学习心得

  

这里写图片描述   javascript是目前web领域中实用最为广泛的语言,不管是在前端还是在后端都能看到它的影子,可以说web从业者不论怎样都绕不开它。在前端领域,各种框架层出不穷,最火的时候几乎每个月都有新的框架诞生,如angularjs,vuejs等。在后端领域,nodejs可谓如火如荼,打破了人们对javascript只能作为前端语言的认知。按照此势头下去,javascript会越来越流行,会随着web的发展越来越重要。现在基本没有第二种语言可以挑战js在web前端中的地位,至少10年以内不可能。   所以不论你是想学各种前端框架还是nodejs,都需要深入理解javascript的工作原理以及特性,只有这样才能以不变应万变。最近看了一些js的教学视频与NC的《JS的高级程序设计》这本书,在这里总结一下js的一些特性,以防自己忘记,也可以方便各位朋友学习与交流。 javascript的实现原理

  javascript是Netscape(网景)公司推出的浏览器端语言,与java没有半点关系,可能想接着java炒火吧。然后js越来越火,网景公司想将其标准化,这样更加利于网络的发展,遂将其提交给了ECMA(欧洲计算机制造商协会)管理,负责对其的标准化。ECMA机构以JS为原型,推出了一个ECMAScript的脚步语言,规定各大浏览器厂商都必须依照ECMAScript标准实现各种的JS,保证JS具有良好的跨平台性。所以可以将ECMAScript看成是标准化的JS,一个意思。   ECMAScript本质上是一种语言规范,其与平台没有关系,比如浏览器等。web浏览器只是ES的宿主环境之一,负责实现ES以及提供ES与环境交互的手段。宿主环境还有Node以及Flash等。   JS的实现要比ES规定的要复杂的多,ES只规定了基本语言特性。浏览器下的JS实现可以由下面三部分组成:  – 语言部分(ES) – 文档对象模型(DOM) – 浏览器对象模型(BOM)   DOM是负责操作由XML编写的应用程序的API,负责将整个页面映射成多层节点结构。如下所示:   

这里写图片描述   DOM可以提供JS对节点结构的任何操作,增删改查等。根据DOM提供的功能多样性,将DOM分为DOM1,DOM2,DOM3这几个级别。DOM1由DOM Core与DOM HTML组成。DOM2在DOM1的基础上提供了更多的操作与功能。DOM3则更进一步的扩展了DOM。   BOM是浏览器对象模型,负责提供浏览器与JS的交互接口,提供JS操作浏览器的窗口与框架等。这个没啥好说的!   总之要实现一个完整的浏览器端JS,这个三个部分缺一不可。 javascript与java,C/C++的区别和联系

  javascript是一门动态语言,即在编写好代码后不用编译,由js解释器解释执行,同时变量不用显式的写出类型,统一用var类型表示,具体的变量类型由JS解释器推测,与python和ruby一样。说到js,大家经常听到面向函数式编程,这是js的一大设计特性。强大的function。其实在js中,函数本质上也是对象,也继承自Object类,也有属性等。js中也很多地方需要我们注意,它与java和C++很不一样。 1. js中没有类继承关键字,和java与C++不一样。js的类继承需要自己动手实现,这也衍生出了多种类继承的编写范式。 2. 同时js中没有函数重载特性,这个需要特别注意。因为在js中函数只是普通对象,没有函数签名(函数名+参数)。而在java和C++中,用函数签名唯一标示一个函数。不过在js中我们也可以有多种方式模拟出函数重载的效果。 3. js中的作用域与java也不一样,js中有作用域链,在函数执行中,解释器会根据执行函数的作用域链一层层的往上寻找变量,一直找到位于末端的window作用域中。 4. js中没有块级作用域。

for (var i = 0; i < 10; i++) { } alert(i);

上述代码是一个简单的for循环,在java等语言中,因为有块级作用域,所以i变量会在for循环执行完后消失。但是在js中,i变量会保持在执行环境中,因为没有块级作用域。所以alert出的结果是10。 5. js中有原型的概念,每个类都有对于的原型,包括函数等。类对象中有引用指向原型对象,所以同一类的原型对象被所有类对象共享。由此衍生出很多有意思的特性。 6. js中有闭包,这个闭包特性是由作用域链的设计衍生出来的,特别值得注意。根据闭包特性,结合匿名函数,我们可以模拟块级作用域效果,甚至可以模拟出单例模式以及私有变量等。 7. js中的继承与多态,需要程序员自己实现,与java和C++不一样。利用js的原型链,可以写出很多不同的继承效果,各有特点。写js中的继承远比java中有技术含量,哈哈! 8. js有垃圾回收机制,但是比较简单,没有jvm中的有意思。

作用域链

  执行环境是js中一个重要的概念。执行环境定义了对象或函数可以访问到的数据。每一个执行环境都有一个与之关联的变量对象,环境定义的所以变量和函数都保存在这个对象中。程序编写者无法正常访问该对象,但是后台的解析器会访问到它。   全局执行环境是最外围的一个执行环境,在web浏览器中是window对象。当某个执行环境执行完后,环境会被销毁,与之相关联的变量对象中的所有变量与函数也可能会被销毁。为什么用可能呢?有一个值得注意的地方,该变量对象销不销毁最本质的是看有没有其他引用指向它,如果有别的引用指向该变量对象,那么该变量对象不会被销毁,比如在闭包中(函数中的函数情况)。   当代码在一个环境中执行时,解析器会创建变量对象的一个作用域链。作用域链的最顶端始终是该执行环境的变量对象。对于函数而言,变量对象是其活动对象!当在执行环境中遇到一个变量时,解析器会从作用域链的最顶端变量对象中找相应的变量,没有找到,则会顺着作用域链一直找下去,最后找到全局执行环境的变量对象!最后还是没有,则会报错! 看下来一个函数:

function compare(value1, value2) { return value2 - value1; }

  上面的函数执行在全局环境中,调用compare()时,会创建一个包含arguments、value1以及value2的对象,this特殊的变量不能在变量对象中找到。所以,全局执行环境中的变量对象则处在compare函数的作用域链中的第二位。如下图所示:   

这里写图片描述   全局变量对象始终存在,像compare函数这样的局部环境的变量对象,只有在函数执行时才存在。首先创建compare函数时,会创建一个预先包含全局变量对象的作用域链,这个作用域链被保存在Scope属性中,Scope属性保存在compare函数对象中。当调用compare函数时,会创建一个执行对象,然后复制scope中的作用域链,将本地函数的活动对象放入作用域链的顶部。注意作用域链是多个引用的数组,本身不保持对象,所以复制作用域链不在内存且非常快速。 原型链

  原型链是JS中实现继承的主要方式。每一个JS类中都有一个指向该类原型对象的引用。该原型对象有一个constructor属性,指向构造函数,如图所示:   

这里写图片描述   由该类生成的对象中,也有个隐含的prototype属性,指向该类的原型对象!设想一下,我们如何将另一个类的对象实例作为某个类的原型对象会怎么样呢?如下所示:   这里写图片描述   可以看到对于instance对象而言,prototype指向的是SubType类的原型,而SubType类的原型是SuperType的类实例,其中的prototype指向SuperType类的原型对象,这样就形成了一个3层的原型链(包含Object原型)。当解析器在instance中寻找变量时,它会先在实例对象中寻找,然后沿着原型链一直向上寻找,直到找到为止!最终如果在Object类的原型中都没有找到,那么会产生错误!   如图所示:   这里写图片描述   根据原型链,我们可以写出JS中的继承代码,一般推荐用混合方式实现,即构造函数与原型链混合方式: function SuperType(name) { this.name = name; this.colors = ["red", "blue"]; } SuperType.prototype.sayName = function() { alert(this.name); } function SubType(name, age) { this.age = age; SuperType.call(this, name); } //继承方法 SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function() { alert(this.Age); } SuperType A = new SuperType("hh"); SubType B = new SubType("MM", 26);

  这样就完成了继承的编写,混合方式的好处,可以避免只用原型链方式的一些缺点,比如不能向构造函数中传递参数,或者对于引用类型的值,不能做到对象独有一份!但是上式方式依然有缺点,可以发现,每次创建SubType类时,会调用SuperType的构造函数,创建两个变量,name与colors。但是我们会发现这两个变量其实在SubType的原型中已经存在了,只是SubType的对象实例中的变量屏蔽了其原型对象中的两个变量!这样一来,造成空间浪费,同时也耗费了在形成SubType原型对象中调用SuperType的构造函数的时间。   那么如何解决上述问题呢,我们可以用寄生混合式继承方法。代码如下:

function inheritPrototype(subType, superType) { var prototype = Object(superType.prototype); prototype.constructor = subType; subType.prototype = prototype; } function SuperType(name) { this.name = name; this.colors = ["red", "blue"]; } SuperType.prototype.sayName = function() { alert(this.name); } function SubType(name, age) { this.age = age; SuperType.call(this, name); } SubType.prototype = inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function() { alert(this.Age); } SuperType A = new SuperType("hh"); SubType B = new SubType("MM", 26);

  采用这种寄生混合式的继承方法,使用寄生式继承父类的prototype对象,将结果做子类的prototype,这样就可以避免调用父类的构造函数,同时需要将prototype对象的constructor属性指向子类构造函数即可。   这种方法是目前公认的最理想的继承范式,能正常使用instanceof和isPrototypeOf()。   思考:这种方式就没有缺点吗?如果后续我们在SuperType的原型对象中增加一个方法,但是SubType的原型是复制品,所以后续的SubType对象实例中不能得到该方法。但是如果采用原型式继承+混合式继承呢?能不能得到更好的效果呢?思考下面这段代码:

function SuperType(name) { this.name = name; this.colors = ["red", "blue"]; } SuperType.prototype.sayName = function() { alert(this.name); } function SubType(name, age) { this.age = age; SuperType.call(this, name); } //原型继承SuperType的原型对象 SubType.prototype = Object.create(SuperType.prototype); SubType.prototype.sayAge = function() { alert(this.Age); } SuperType A = new SuperType("hh"); SubType B = new SubType("MM", 26); //增加这段代码 SuperType.prototype.sayColors = function() { alert(this.colors); } B.sayColors(); 闭包

  闭包是JS中的一个非常重要的概念。闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包常见的方式是在一个函数内部建立另一个函数,例如:

function createCompare(propertyName) { return function(object1, object2) { var value1 = object1[propertyName]; var value2 = object2[propertyName]; return value2 - value1; } } var compare = createCompare("name"); var result = compare({name: "haha"}, {name: "hehe"});

  该函数返回一个匿名函数,在该匿名函数中可以访问外面函数的活动变量propertyName。该原理是:在匿名函数返回以后,匿名函数的作用域链被初始化为包含createCompare()函数的活动对象以及全局变量对象。这样,在匿名函数执行时就可以访问createCompare函数的活动变量了。值得注意的是,createCompare函数在执行完毕后,它的变量对象并没有被销毁,因为有匿名函数的作用域链依然在引用这个活动对象。换句话说,createCompare函数执行完后,它的作用域链会被销毁,但是它的活动变量却保留在了内存中,直到匿名函数被销毁后,它的活动对象才会被销毁。用下图表示:   

这里写图片描述 匿名函数

  java中有匿名对象,js中有匿名函数,其实本质都差不多。js中函数对象都有一个name属性。对于name属性,其实是指向函数声明时跟在function后面的名字。但是在匿名函数中name为空字符串。这里需要正确理解函数声明与函数表达式。   函数声明:

functionName(a, b); //由于函数声明提升,所以可以执行 function functionName(arg0, arg1) { } 函数表达式: a(); //函数表示式,,没有函数声明提升,所以不能执行,报错! var a = function(arg0, arg1) { }; 在递归情况下,可以用匿名函数很好的书写,即使在严格模式下,依然可以使用: var factorial = (function f(num) { if (num //设置私有变量与私有函数 var privateVariable = 10; function privateFunction(){ alert("hello world"); } //创建对象,可以是任意类型的对象 var object = new Object(); //添加特权/公有属性与方法 object.publicProperty = true; object.publicMethod = function(){ privateVariable++; return privateFunction(); }; return object; })(); 版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由思创斯整理,转载请注明出处:https://ispacesoft.com/109202.html

赞 (0) 思创斯忠实用户-ss思创斯忠实用户-ss 0 0 生成海报


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有