前端的一些知识储备

转载自:https://www.cnblogs.com/jackyWHJ/p/4326671.html

一、JavaScript的对象。
JavaScript 中所有变量都是对象:字符串、数值、数组、函数…,除了两个例外 null 和 undefined。JavaScript 的对象只是带有属性和方法的特殊数据类型,
可以作为哈希表使用,主要用来保存命名的键与值的对应关系。JavaScript 提供多个内建对象,比如 String、Date、Array 等等。
此外,JavaScript 允许自定义对象,有两种不同的方法:

定义并创建对象的实例
使用函数来定义对象,然后创建新的对象实例
1、创建直接的实例

person=new Object();
person.firstname=“Bill”;
person.lastname=“Gates”;
person.age=56;
person.eyecolor=“blue”;
这个例子创建了对象的一个新实例,并向其添加了四个属性;此外,我们也可以通过对象字面量直接创建对象实例:person={firstname:“John”,lastname:“Doe”,age:50,eyecolor:“blue”};

2、使用对象构造器

使用函数来构造对象:

function person(firstname,lastname,age,eyecolor)
{
this.firstname=firstname;
this.lastname=lastname;
this.age=age;
this.eyecolor=eyecolor;
} 
参照来源:http://www.w3school.com.cn/js/js_objects.asp

二、JavaScript的面向对象。
  Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。JavaScript 不包含传统的类继承模型,而是使用 prototype 原型模型。虽然这经常被当作是 JavaScript 的缺点被提及,其实基于原型的继承模型比传统的类继承还要强大。那么javascript是如何去实现继承的呢?

比如,现在有一个"动物"对象的构造函数。

function Animal(){
  this.species = “动物”;
}
还有一个"猫"对象的构造函数。

function Cat(name,color){
  this.name = name;
  this.color = color;
}
怎样才能使"猫"继承"动物"呢?

使用prototype属性。
如果"猫"的prototype对象,指向一个Animal的实例,那么所有"猫"的实例,就能继承Animal了。
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
var cat1 = new Cat(“大毛”,“黄色”);
alert(cat1.species); // 动物
代码的第一行,我们将Cat的prototype对象指向一个Animal的实例。

Cat.prototype = new Animal();
它相当于完全删除了prototype 对象原先的值,然后赋予一个新值。但是,第二行又是什么意思呢?

Cat.prototype.constructor = Cat;
 原来,任何一个prototype对象都有一个constructor属性,指向它的构造函数。如果没有"Cat.prototype = new Animal();"这一行,Cat.prototype.constructor是指向Cat的;加了这一行以后Cat.prototype.constructor指向Animal。

alert(Cat.prototype.constructor == Animal); //true
更重要的是,每一个实例也有一个constructor属性,默认调用prototype对象的constructor属性。

alert(cat1.constructor == Cat.prototype.constructor); // true
因此,在运行"Cat.prototype = new Animal();"这一行之后,cat1.constructor也指向Animal!  
1
alert(cat1.constructor == Animal); // true
这显然会导致继承链的紊乱(cat1明明是用构造函数Cat生成的),因此我们必须手动纠正,将Cat.prototype对象的constructor值改为Cat。这就是第二行的意思。
这是很重要的一点,编程时务必要遵守。下文都遵循这一点,即如果替换了prototype对象,

o.prototype = {};
 
那么,下一步必然是为新的prototype对象加上constructor属性,并将这个属性指回原来的构造函数。

o.prototype.constructor = o;
这里还有另外一种方法,就是直接继承prototype,这种方法是对第一种方法的改进。由于Animal对象中,不变的属性都可以直接写入Animal.prototype。所以,我们也可以让Cat()跳过 Animal(),直接继承Animal.prototype。

现在,我们先将Animal对象改写:

function Animal(){ }
Animal.prototype.species = “动物”;
然后,将Cat的prototype对象,然后指向Animal的prototype对象,这样就完成了继承。

Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat1 = new Cat(“大毛”,“黄色”);
alert(cat1.species); // 动物
与前一种方法相比,这样做的优点是效率比较高(不用执行和建立Animal的实例了),比较省内存。缺点是 Cat.prototype和Animal.prototype现在指向了同一个对象,那么任何对Cat.prototype的修改,都会反映到Animal.prototype。
所以,上面这一段代码其实是有问题的。请看第二行 
1
Cat.prototype.constructor = Cat;
这一句实际上把Animal.prototype对象的constructor属性也改掉了! 
1
alert(Animal.prototype.constructor); // Cat
参照来源:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html 想要了解更多继承实现的小伙伴可以看下这个博客

三、上下文(this的理解)。
JavaScript 有一套完全不同于其它语言的对 this 的处理机制。在五种不同的情况下 ,this 指向的各不相同。
1、全局范围内this;

当在全部范围内使用 this,它将会指向全局对象。浏览器中运行的 JavaScript 脚本,这个全局对象是 window。
2、函数调用
foo();
这里 this 也会指向全局对象。
ES5 注意: 在严格模式下(strict mode),不存在全局变量。 这种情况下 this 将会是 undefined。
3、方法调用
test.foo();
这个例子中,this 指向 test 对象。
4、调用构造函数

new foo();
如果函数倾向于和 new 关键词一块使用,则我们称这个函数是 构造函数。在函数内部,this 指向新创建的对象。
5、显式的设置 this
function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // 数组将会被扩展,如下所示
foo.call(bar, 1, 2, 3); // 传递到foo的参数是:a = 1, b = 2, c = 3
当使用 Function.prototype 上的 call 或者 apply 方法时,函数内的 this 将会被 显式设置为函数调用的第一个参数。
因此函数调用的规则在上例中已经不适用了,在foo 函数内 this 被设置成了 bar。

注意: 在对象的字面声明语法中,this 不能用来指向对象本身。 因此 var obj = {me: this} 中的 me 不会指向 obj,因为 this 只可能出现在上述的五种情况中。 译者注:这个例子中,如果是在浏览器中运行,obj.me 等于 window 对象。
参照来源:http://www.jb51.net/onlineread/JavaScript-Garden-CN/#function.this

四、闭包
“官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
相信很少有人能直接看懂这句话,因为他描述的太学术。其实这句话通俗的来说就是:JavaScript中所有的function都是一个闭包。不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”。看下面这段代码:

function a() {
var i = 0;
function b() {
alert(++i);
}
return b;
}
var c = a();
c();
这段代码有两个特点:
函数b嵌套在函数a内部;
函数a返回函数b。
引用关系如图:

这样在执行完var c=a()后,变量c实际上是指向了函数b,b中用到了变量i,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说:
当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个我们通常所谓的“闭包”。
让我们说的更透彻一些。所谓“闭包”,就是在构造函数体内定义另外的函数作为目标对象的方法函数,而这个对象的方法函数反过来引用外层外层函数体中 的临时变量。这使得只要目标 对象在生存期内始终能保持其方法,就能间接保持原构造函数体当时用到的临时变量值。尽管最开始的构造函数调用已经结束,临时变量的名称也都消失了,但在目 标对象的方法内却始终能引用到该变量的值,而且该值只能通这种方法来访问。即使再次调用相同的构造函数,但只会生成新对象和方法,新的临时变量只是对应新 的值,和上次那次调用的是各自独立的。
简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。、
闭包的应用场景

保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。
通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问)推荐阅读:http://javascript.crockford.com/private.html
私有属性和方法在Constructor外是无法被访问的

function Constructor(…) {
var that = this;
var membername = value;
function membername(…) {…}
}
以上3点是闭包最基本的应用场景,很多经典案例都源于此。
参照来源:http://blog.csdn.net/adeyi/article/details/8808046 要理解更多的小伙伴可以访问该链接

五、Javascript模块化开发的实现

var module1 = (function(){
  var _count = 0;
  var m1 = function(){
      //…
  };
  var m2 = function(){
      //…
  };
  return {
    m1 : m1,
    m2 : m2
  };
})();
参照来源:http://www.ruanyifeng.com/blog/2012/10/javascript_module.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值