javascript原型和原型链有什么特点

编程语言及工具

100人已加入

描述

  javascript中的原型链

  要弄清楚原型链就要先弄清楚 function 类型,在javascript中没有类的概念,都是函数,所以它是一门函数式的编程语言。类有一个很重要的特性,就是它可以根据它的构造函数来创建以它为模板的对象。在javascript中,函数就有2个功能

  第一、 作为一般函数调用

  第二、 作为它原型对象的构造函数 也就new()

  我们来看一个例子

  [javascript] view plain copyfunction a(){

  this.name = ‘a’;

  }

  当创建一个函数,它会发生什么呢?

  第一、它会创建1个函数对象 也就是a 本身

  第二、它会创建1个原型对象@a(用@来表示)

  第三、函数对象会有一个prototype指针,它指向了对应的原型对象,这里就指向了@a

  第四、@a对象中有一个construtor指针,指向它的构造函数,这里就指向了a

  这个prototype属性究竟有什么用呢?

  其实prototype 属性表示当前函数能够控制的范围(或者说它指明了当前函数是谁的构造函数),这里a就是@a原型对象的构造函数,所以我们会看见有这种写法

  [javascript] view plain copyfunction a(){

  this.name = ‘a’;

  }

  var a1 = new a();

  这就和其他常见语言相似了,new 就是调用原型对象(通过prototype指针)里面构造函数(constructor)创建一个新的对象实例。

  那么修改了prototype指向对象里面的属性,也就影响了所有以它为模板创建的实例,我们可以这样来验证

  [javascript] view plain copyfunction a(){

  this.name = ‘a’;

  }

  var a1 = new a();

  a.prototype.age = 1;

  alert(a1.age);

  结果:1

  那为什么a1对象可以直接访问到age属性呢?a1对象里面我并没有定义age属性啊,

  那是因为所有实例里面都会有一个引用_proto_(在firfox,chrome下可以直接访问,ie不支持)指向了这个原型,这里就是指向了@a,

  [javascript] view plain copyfunction a(){

  this.name = ‘a’;

  }

  var a1 = new a();

  alert(a1._proto_ == a.prototype)

  结果:true

  在访问属性的时候,会先在a1对象内部中寻找,如果没有,就会顺着_proto_指向的对象里面去寻找,这里会到@a中寻找,找到就返回值,没有找到就返回undefined,用个成语来形容,就是顺藤摸瓜嘛!

  至此原型链的含义就出来了,由于原型对象也有一个_proto_指针,又指向了另一个原型,一个接一个,就形成了原型链。Object.prototype是最顶层的原型,所以如果修改了Object.prototype的属性,那么就影响了所有的对象。

  在来看一段代码

  [javascript] view plain copyfunction a(){

  this.name = ‘a’;

  }

  function b(){

  this.age = 1;

  }

  b.prototype = new a();

  alert(new b().name);

  我们显示的将b的原型指向了a的一个实例,然后,b的实例也可以访问a的属性了。这就是javascript的继承了,那为什么b.prototype 指向的是a的一个实例,而不是直接指向a.prototype 呢?

  [javascript] view plain copyb.prototype = new a.prototype;

  如果像上面这么写,修改p.prototype中的属性,那么a的原型也会改变了,相当于是子类修改了父类,并且子类和父类的属性糅合在了一起,这显然是不合适的。换句话说,b也成为了@a的构造函数,a,b成了平级的关系。

  我们可以下一个定义:

  函数a 继承函数b 也就是让函数a成为函数b原型的一个实例的构造函数,构造函数里面声明的属性是函数a自己的,原型实例里面的属性就是继承b的

  [javascript] view plain copyvar $ = jQuery = function(selector,context){

  //不可能在自己的构造函数中又一次构造自己,所以返回了另外一个构造函数的实例

  return new init(selector,context);

  }

  jQuery.fn = jQuery.prototype = {

  size:function(){

  return this.length;

  }

  }

  function init (selector,context){

  }

  init.prototype = jQuery.fn;;

  }

  这是jquery的一段源码,我们在使用jquery的时候,并没有使用new关键字,那它是如何构造对象的呢?

  用上面的知识,可以解释,jquery这里只是一个一般函数的调用,它返回了jquery原型的另外一个构造函数创建的对象,也就是new init()

  JavaScript中的原型

  原型是JavaScript中一个比较难理解的概念,原型相关的属性也比较多,对象有“[[prototype]]”属性,函数对象有“prototype”属性,原型对象有“constructor”属性。

  认识原型

  开始原型的介绍之前,首先来认识一下什么是原型?

  在JavaScript中,原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript的对象中都包含了一个“ [[Prototype]]”内部属性,这个属性所对应的就是该对象的原型。

  “[[Prototype]]”作为对象的内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,Firefox和Chrome中提供了“__proto__”这个非标准(不是所有浏览器都支持)的访问器(ECMA引入了标准对象原型访问器“Object.getPrototype(object)”)。

  实例分析

  下面通过一个例子来看看原型相关概念:

  function Person(name, age){

  this.name = name;

  this.age = age;

  this.getInfo = function(){

  console.log(this.name + “ is ” + this.age + “ years old”);

  };

  }

  var will = new Person(“Will”, 28);

  在上面的代码中,通过了Person这个构造函数创建了一个will对象。下面就通过will这个对象一步步展开了解原型。

  Step 1: 查看对象will的原型

  通过下面代码,可以查看对象will的原型:

  console.log(will.__proto__);

  console.log(will.constructor);

  结果分析:

  “Person {}”对象就是对象will的原型,通过Chrome展开可以看到,“Person {}”作为一个原型对象,也有“__proto__”属性(对应原型的原型)。

  在这段代码中,还用到了“constructor”属性。在JavaScript的原型对象中,还包含一个“constructor”属性,这个属性对应创建所有指向该原型的实例的构造函数。

  通过“constructor”这个属性,我们可以来判断一个对象是不是数组类型

  function isArray(myArray) {

  return myArray.constructor.toString().indexOf(“Array”) 》 -1;

  }

  在这里,will对象本身并没有“constructor”这个属性,但是通过原型链查找,找到了will原型(will.__proto__)的“constructor”属性,并得到了Person函数。

  javascript

  Step 2: 查看对象will的原型(will.__proto__)的原型

  既然will的原型“Person {}”也是一个对象,那么我们就同样可以来查看“will的原型(will.__proto__)的原型”。

  运行下面的代码:

  console.log(will.__proto__ === Person.prototype);

  console.log(Person.prototype.__proto__);

  console.log(Person.prototype.constructor);

  console.log(Person.prototype.constructor === Person);

  结果分析:

  首先看 “will.__proto__ === Person.prototype”,在JavaScript中,每个函数都有一个prototype属性,当一个函数被用作构造函数来创建实例时,该函数的prototype属性值将被作为原型赋值给所有对象实例(也就是设置实例的__proto__属性),也就是说,所有实例的原型引用的是函数的prototype属性。了解了构造函数的prototype属性之后,一定就明白为什么第一句结果为true了。

  prototype属性是函数对象特有的,如果不是函数对象,将不会有这样一个属性。

  当通过“Person.prototype.__proto__”语句获取will对象原型的原型时候,将得到“Object {}”对象,后面将会看到所有对象的原型都将追溯到“Object {}”对象。

  对于原型对象“Person.prototype”的“constructor”,根据前面的介绍,将对应Person函数本身。

  通过上面可以看到,“Person.prototype”对象和Person函数对象通过“constructor”和“prototype”属性实现了相互引用(后面会有图展示这个相互引用的关系)。

  javascript

  Step 3: 查看对象Object的原型

  通过前一部分可以看到,will的原型的原型是“Object {}”对象。实际上在JavaScript中,所有对象的原型都将追溯到“Object {}”对象。

  下面通过一段代码看看“Object {}”对象:

  console.log(Person.prototype.__proto__ === Object.prototype);

  console.log(typeof Object);

  console.log(Object);

  console.log(Object.prototype);

  console.log(Object.prototype.__proto__);

  console.log(Object.prototype.constructor);

  通过下面的代码可以看到:

  Object对象本身是一个函数对象。

  既然是Object函数,就肯定会有prototype属性,所以可以看到“Object.prototype”的值就是“Object {}”这个原型对象。

  反过来,当访问“Object.prototype”对象的“constructor”这个属性的时候,就得到了Obejct函数。

  另外,当通过“Object.prototype.__proto__”获取Object原型的原型的时候,将会得到“null”,也就是说“Object {}”原型对象就是原型链的终点了。

  javascript

  Step 4: 查看对象Function的原型

  在上面的例子中,Person是一个构造函数,在JavaScript中函数也是对象,所以,我们也可以通过“__proto__”属性来查找Person函数对象的原型。

  console.log(Person.__proto__ === Function.prototype);

  console.log(Person.constructor === Function)

  console.log(typeof Function);

  console.log(Function);

  console.log(Function.prototype);

  console.log(Function.prototype.__proto__);

  console.log(Function.prototype.constructor);

  结果分析 :

  在JavaScript中有个Function对象(类似Object),这个对象本身是个函数;所有的函数(包括Function,Object)的原型(__proto__)都是“Function.prototype”。

  Function对象作为一个函数,就会有prototype属性,该属性将对应“function () {}”对象。

  Function对象作为一个对象,就有“__proto__”属性,该属性对应“Function.prototype”,也就是说,“Function.__proto__ === Function.prototype”

  对于Function的原型对象“Function.prototype”,该原型对象的“__proto__”属性将对应“Object {}”

  javascript

  对比prototype和__proto__

  对于“prototype”和“__proto__”这两个属性有的时候可能会弄混,“Person.prototype”和“Person.__proto__”是完全不同的。

  在这里对“prototype”和“__proto__”进行简单的介绍:

  对于所有的对象,都有__proto__属性,这个属性对应该对象的原型

  对于函数对象,除了__proto__属性之外,还有prototype属性,当一个函数被用作构造函数来创建实例时,该函数的prototype属性值将被作为原型赋值给所有对象实例(也就是设置实例的__proto__属性)

  图解实例

  通过上面结合实例的分析,相信你一定了解了原型中的很多内容。

  但是现在肯定对上面例子中的关系感觉很凌乱,一会儿原型,一会儿原型的原型,还有Function,Object,constructor,prototype等等关系。

  现在就对上面的例子中分析得到的结果/关系进行图解,相信这张图可以让你豁然开朗。

  javascript

  对于上图的总结如下:

  所有的对象都有“__proto__”属性,该属性对应该对象的原型

  所有的函数对象都有“prototype”属性,该属性的值会被赋值给该函数创建的对象的“__proto__”属性

  所有的原型对象都有“constructor”属性,该属性对应创建所有指向该原型的实例的构造函数

  函数对象和原型对象通过“prototype”和“constructor”属性进行相互关联

  通过原型改进例子

  在上面例子中,“getInfo”方法是构造函数Person的一个成员,当通过Person构造两个实例的时候,每个实例都会包含一个“getInfo”方法。

  var will = new Person(“Will”, 28);

  var wilber = new Person(“Wilber”, 27);

  javascript

  前面了解到,原型就是为了方便实现属性的继承,所以可以将“getInfo”方法当作Person原型(Person.__proto__)的一个属性,这样所有的实例都可以通过原型继承的方式来使用“getInfo”这个方法了。

  所以对例子进行如下修改:

  function Person(name, age){

  this.name = name;

  this.age = age;

  }

  Person.prototype.getInfo = function(){

  console.log(this.name + “ is ” + this.age + “ years old”);

  };

  修改后的结果为:

  javascript

  原型链

  因为每个对象和原型都有原型,对象的原型指向对象的父,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。

  在“理解JavaScript的作用域链”一文中,已经介绍了标识符和属性通过作用域链和原型链的查找。

  这里就继续看一下基于原型链的属性查找。

  属性查找

  当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部(也就是 “Object.prototype”), 如果仍然没有找到指定的属性,就会返回 undefined。

  看一个例子:

  function Person(name, age){

  this.name = name;

  this.age = age;

  }

  Person.prototype.MaxNumber = 9999;

  Person.__proto__.MinNumber = -9999;

  var will = new Person(“Will”, 28);

  console.log(will.MaxNumber);

  // 9999

  console.log(will.MinNumber);

  // undefined

  在这个例子中分别给“Person.prototype ”和“ Person.__proto__”这两个原型对象添加了“MaxNumber ”和“MinNumber”属性,这里就需要弄清“prototype”和“__proto__”的区别了。

  “Person.prototype ”对应的就是Person构造出来所有实例的原型,也就是说“Person.prototype ”属于这些实例原型链的一部分,所以当这些实例进行属性查找时候,就会引用到“Person.prototype ”中的属性。

  属性隐藏

  当通过原型链查找一个属性的时候,首先查找的是对象本身的属性,如果找不到才会继续按照原型链进行查找。

  这样一来,如果想要覆盖原型链上的一些属性,我们就可以直接在对象中引入这些属性,达到属性隐藏的效果。

  看一个简单的例子:

  function Person(name, age){

  this.name = name;

  this.age = age;

  }

  Person.prototype.getInfo = function(){

  console.log(this.name + “ is ” + this.age + “ years old”);

  };

  var will = new Person(“Will”, 28);

  will.getInfo = function(){

  console.log(“getInfo method from will instead of prototype”);

  };

  will.getInfo();

  // getInfo method from will instead of prototype

  对象创建方式影响原型链

  会到本文开始的例子,will对象通过Person构造函数创建,所以will的原型(will.__proto__)就是“Person.prototype”。

  同样,我们可以通过下面的方式创建一个对象:

  var July = {

  name: “July”,

  age: 28,

  getInfo: function(){

  console.log(this.name + “ is ” + this.age + “ years old”);

  },

  }

  console.log(July.getInfo());

  当使用这种方式创建一个对象的时候,原型链就变成下图了,July对象的原型是“Object.prototype”也就是说对象的构建方式会影响原型链的形式。

  javascript

  hasOwnProperty

  “hasOwnProperty”是“Object.prototype”的一个方法,该方法能判断一个对象是否包含自定义属性而不是原型链上的属性,因为“hasOwnProperty” 是 JavaScript 中唯一一个处理属性但是不查找原型链的函数。

  相信你还记得文章最开始的例子中,通过will我们可以访问“constructor”这个属性,并得到will的构造函数Person。这里结合“hasOwnProperty”这个函数就可以看到,will对象并没有“constructor”这个属性。

  从下面的输出可以看到,“constructor”是will的原型(will.__proto__)的属性,但是通过原型链的查找,will对象可以发现并使用“constructor”属性。

  javascript

  “hasOwnProperty”还有一个重要的使用场景,就是用来遍历对象的属性。

  function Person(name, age){

  this.name = name;

  this.age = age;

  }

  Person.prototype.getInfo = function(){

  console.log(this.name + “ is ” + this.age + “ years old”);

  };

  var will = new Person(“Will”, 28);

  for(var attr in will){

  console.log(attr);

  }

  // name

  // age

  // getInfo

  for(var attr in will){

  if(will.hasOwnProperty(attr)){

  console.log(attr);

  }

  }

  // name

  // age

  javascript原型和原型链有什么特点

  每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时,

  如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,

  于是就这样一直找下去,也就是我们平时所说的原型链的概念。

  关系:instance.constructor.prototype = instance.__proto__

  特点:

  JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。

  当我们需要一个属性的时,Javascript引擎会先看当前对象中是否有这个属性, 如果没有的话,

  就会查找他的Prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象。

  function Func(){}

  Func.prototype.name = “Sean”;

  Func.prototype.getInfo = function() {

  return this.name;

  }

  var person = new Func();//现在可以参考var person = Object.create(oldObject);

  console.log(person.getInfo());//它拥有了Func的属性和方法

  //“Sean”

  console.log(Func.prototype);

  // Func { name=“Sean”, getInfo=function()}

  写一个通用的事件侦听器函数。

  // event(事件)工具集,来源:github.com/markyun

  markyun.Event = {

  // 页面加载完成后

  readyEvent : function(fn) {

  if (fn==null) {

  fn=document;

  }

  var oldonload = window.onload;

  if (typeof window.onload != ‘function’) {

  window.onload = fn;

  } else {

  window.onload = function() {

  oldonload();

  fn();

  };

  }

  },

  // 视能力分别使用dom0||dom2||IE方式 来绑定事件

  // 参数: 操作的元素,事件名称 ,事件处理程序

  addEvent : function(element, type, handler) {

  if (element.addEventListener) {

  //事件类型、需要执行的函数、是否捕捉

  element.addEventListener(type, handler, false);

  } else if (element.attachEvent) {

  element.attachEvent(‘on’ + type, function() {

  handler.call(element);

  });

  } else {

  element[‘on’ + type] = handler;

  }

  },

  // 移除事件

  removeEvent : function(element, type, handler) {

  if (element.removeEventListener) {

  element.removeEventListener(type, handler, false);

  } else if (element.datachEvent) {

  element.detachEvent(‘on’ + type, handler);

  } else {

  element[‘on’ + type] = null;

  }

  },

  // 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)

  stopPropagation : function(ev) {

  if (ev.stopPropagation) {

  ev.stopPropagation();

  } else {

  ev.cancelBubble = true;

  }

  },

  // 取消事件的默认行为

  preventDefault : function(event) {

  if (event.preventDefault) {

  event.preventDefault();

  } else {

  event.returnValue = false;

  }

  },

  // 获取事件目标

  getTarget : function(event) {

  return event.target || event.srcElement;

  },

  // 获取event对象的引用,取到事件的所有信息,确保随时能使用event;

  getEvent : function(e) {

  var ev = e || window.event;

  if (!ev) {

  var c = this.getEvent.caller;

  while (c) {

  ev = c.arguments[0];

  if (ev && Event == ev.constructor) {

  break;

  }

  c = c.caller;

  }

  }

  return ev;

  }

  };

  对Node的优点和缺点提出了自己的看法?

  *(优点)因为Node是基于事件驱动和无阻塞的,所以非常适合处理并发请求,

  因此构建在Node上的代理服务器相比其他技术实现(如Ruby)的服务器表现要好得多。

  此外,与Node代理服务器交互的客户端代码是由javascript语言编写的,

  因此客户端和服务器端都用同一种语言编写,这是非常美妙的事情。

  *(缺点)Node是一个相对新的开源项目,所以不太稳定,它总是一直在变,

  而且缺少足够多的第三方库支持。看起来,就像是Ruby/Rails当年的样子。

  Javascript如何实现继承?

  1、构造继承

  2、原型继承

  3、实例继承

  4、拷贝继承

  原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式。

  function Parent(){

  this.name = ‘wang’;

  }

  function Child(){

  this.age = 28;

  }

  Child.prototype = new Parent();//继承了Parent,通过原型

  var demo = new Child();

  alert(demo.age);

  alert(demo.name);//得到被继承的属性

  }

  Javascript作用链域?

  全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节。

  当需要从局部函数查找某一属性或方法时,如果当前作用域没有找到,就会上溯到上层作用域查找,

  直至全局函数,这种组织形式就是作用域链。

  javascript创建对象的几种方式?

  javascript创建对象简单的说,无非就是使用内置对象或各种自定义对象,当然还可以用JSON;但写法有很多种,也能混合使用。

  1、对象字面量的方式

  person={firstname:“Mark”,lastname:“Yun”,age:25,eyecolor:“black”};

  2、用function来模拟无参的构造函数

  function Person(){}

  var person=new Person();//定义一个function,如果使用new“实例化”,该function可以看作是一个Class

  person.name=“Mark”;

  person.age=“25”;

  person.work=function(){

  alert(person.name+“ hello.。。”);

  }

  person.work();

  3、用function来模拟参构造函数来实现(用this关键字定义构造的上下文属性)

  function Pet(name,age,hobby){

  this.name=name;//this作用域:当前对象

  this.age=age;

  this.hobby=hobby;

  this.eat=function(){

  alert(“我叫”+this.name+“,我喜欢”+this.hobby+“,是个程序员”);

  }

  }

  var maidou =new Pet(“麦兜”,25,“coding”);//实例化、创建对象

  maidou.eat();//调用eat方法

  4、用工厂方式来创建(内置对象)

  var wcDog =new Object();

  wcDog.name=“旺财”;

  wcDog.age=3;

  wcDog.work=function(){

  alert(“我是”+wcDog.name+“,汪汪汪。。。。。。”);

  }

  wcDog.work();

  5、用原型方式来创建

  function Dog(){

  }

  Dog.prototype.name=“旺财”;

  Dog.prototype.eat=function(){

  alert(this.name+“是个吃货”);

  }

  var wangcai =new Dog();

  wangcai.eat();

  5、用混合方式来创建

  function Car(name,price){

  this.name=name;

  this.price=price;

  }

  Car.prototype.sell=function(){

  alert(“我是”+this.name+“,我现在卖”+this.price+“万元”);

  }

  var camry =new Car(“凯美瑞”,27);

  camry.sell();

  CSS优先级算法如何计算? * 优先级就近原则,同权重情况下样式定义最近者为准;

  载入样式以最后载入的定位为准;

  优先级为:

  !important 》 id 》 class 》 tag

  important 比 内联优先级高

  iframe有那些缺点?

  *iframe会阻塞主页面的Onload事件;

  *搜索引擎的检索程序无法解读这种页面,不利于SEO;

  *iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载。

  使用iframe之前需要考虑这两个缺点。如果需要使用iframe,最好是通过javascript

  动态给iframe添加src属性值,这样可以绕开以上两个问题。

  HTML5的离线储存怎么使用,工作原理能不能解释一下?

  在用户没有与因特网连接时,可以正常访问站点或应用,在用户与因特网连接时,更新用户机器上的缓存文件。

  原理:HTML5的离线存储是基于一个新建的.appcache文件的缓存机制(不是存储技术),通过这个文件上的解析清单离线存储资源,这些资源就会像cookie一样被存储了下来。之后当网络在处于离线状态下时,浏览器会通过被离线存储的数据进行页面展示。

  如何使用:

  1、页面头部像下面一样加入一个manifest的属性;

  2、在cache.manifest文件的编写离线存储的资源;

  CACHE MANIFEST

  #v0.11

  CACHE:

  js/app.js

  css/style.css

  NETWORK:

  resourse/logo.png

  FALLBACK:

  / /offline.html

  3、在离线状态时,操作window.applicationCache进行需求实现。

  Ajax是什么? 如何创建一个Ajax?

  ajax的全称:AsynchronousJavascript And XML。

  异步传输+js+xml。

  所谓异步,在这里简单地解释就是:向服务器发送请求的时候,我们不必等待结果,而是可以同时做其他的事情,等到有了结果它自己会根据设定进行后续操作,与此同时,页面是不会发生整页刷新的,提高了用户体验。

  (1)创建XMLHttpRequest对象,也就是创建一个异步调用对象

  (2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息

  (3)设置响应HTTP请求状态变化的函数

  (4)发送HTTP请求

  (5)获取异步调用返回的数据

  (6)使用JavaScript和DOM实现局部刷新

  同步和异步的区别?

  同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,j进行下一步操作。

  异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容。

  AMD(Modules/Asynchronous-Definition)、CMD(Common ModuleDefinition)规范区别?

  AsynchronousModule Definition,异步模块定义,所有的模块将被异步加载,模块加载不影响后面语句运行。所有依赖某些模块的语句均放置在回调函数中。

  区别:

  1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.

  2. CMD 推崇依赖就近,AMD 推崇依赖前置。看代码:

  // CMD

  define(function(require,exports, module) {

  var a = require(‘。/a’)

  a.doSomething()

  // 此处略去 100 行

  var b = require(‘。/b’) // 依赖可以就近书写

  b.doSomething()

  // 。。。

  })

  // AMD 默认推荐

  define([‘。/a’,‘。/b’], function(a, b) { // 依赖必须一开始就写好

  a.doSomething()

  // 此处略去 100 行

  b.doSomething()

  // 。。。

  })

  DOM操作——怎样添加、移除、移动、复制、创建和查找节点?

  (1)创建新节点

  createDocumentFragment() //创建一个DOM片段

  createElement() //创建一个具体的元素

  createTextNode() //创建一个文本节点

  (2)添加、移除、替换、插入

  appendChild()

  removeChild()

  replaceChild()

  insertBefore() //在已有的子节点前插入一个新的子节点

  (3)查找

  getElementsByTagName() //通过标签名称

  getElementsByName() //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)

  getElementById() //通过元素Id,唯一性

  什么叫优雅降级和渐进增强?

  优雅降级:Web站点在所有新式浏览器中都能正常工作,如果用户使用的是老式浏览器,则代码会针对旧版本的IE进行降级处理了,使之在旧式浏览器上以某种形式降级体验却不至于完全不能用。

  如:border-shadow

  渐进增强:从被所有浏览器支持的基本功能开始,逐步地添加那些只有新版本浏览器才支持的功能,向页面增加不影响基础浏览器的额外样式和功能的。当浏览器支持时,它们会自动地呈现出来并发挥作用。

  如:默认使用flash上传,但如果浏览器支持HTML5 的文件上传功能,则使用HTML5实现更好的体验;

  jsonp的原理是动态插入script标签

  跨子域可以采用iframe proxy的方式,支持GET和POST,支持异步POST。缺点是:范围较窄,限定在“跨子域”,而且需要在目标服务器增加额外的文件。

  JSONP的方式,支持双向通信。只支持GET。缺点是:不支持POST,同时需要目标服务器在服务端支持。

  iframe的window.name的方式,支持跨主域。缺点是:不支持POST,不过已经很赞了:)

  HTML5postMessage,支持双向通信。缺点是:仅限于HTML5。结合window.name的方式,就很赞了

  iframe + location.hash的方式跨主域,功能强大,兼容性好,支持跨域的js调用,支持双向通信。缺点是:太复杂,会嵌套太多的iframe,同时数据直接写在url中,数据大小受限而且数据暴露在外。

  利用Flash跨域,优点是支持强大,相对简单。缺点是:依赖flash,需要在服务器更目录放置crossdomain.xml文件。

  为什么要有同源限制?

  我们举例说明:比如一个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。

  作用域链的理解

  每一段js代码(全局代码或函数)都有一个与之关联的作用域链(scope chain)。

  当js需要查找变量x值的时候(这个过程称为变量解析(variable resolution)),它会从链的第一个对象开始查找,如果这个对象有一个名为x的属性,则会直接使用这个属性的值,如果第一个对象中没有名为x的属性,js会继续查找链上的下一个对象。如果第二个对象依然没有名为x的属性,则会继续查找下一个,以此类推。

  如果作用域链上没有任何一个对象含有属性x,那么就认为这段代码的作用域链上不存在x,并最终抛出一个引用错误(ReferenceError)异常。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分