查看“JavaScript”的源代码
←
JavaScript
跳转至:
导航
、
搜索
因为以下原因,你没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看并复制此页面的源代码:
==库、框架== <div id="indexContent"> [[jquery]] [[ExtJS]] [[ExtJS6]] [[BackboneJS]] [[RequireJS]] [[d3]] [[kendo ui]] [[ember]] [[reactjs]] [[Vue]] [[Angular2]] [[Ant Design]] </div> * [http://www.highcharts.com/download Highcharts] * [http://isotope.metafizzy.co/ Isotope] * [http://masonry.desandro.com/ masonry] * [http://www.melonjs.org/ melonJS] * [http://www.jacklmoore.com/autosize/ autosize] * [http://zeptojs.com/ Zepto.js] * [http://bouncejs.com/ bounce.js] * [http://www.gruntjs.net grunt] ==Js构造函数== https://www.jianshu.com/p/5f38069a4acc ===常规姿势=== <source lang="javascript"> //声明一个"人"的构造函数,目的是通过new出来的对象都是一个个的具体的"人" var Person = function () { var prx = "other"; //私有属性,该属性new出来的对象时无法获取到的。 var prxMethond = function () { console.log("in prxMethod"); }; //用var申明私有方法,该方法不能被new Person调用到。一般的,我们只需要再内部使用到的方法可最好声明称私有方法。 this.name = "double"; //定义实例属性,也就是说,通过new出来的对象都具备这个属性。 this.say = function () { console.log("hi i am " + this.name); } //say是一个实例方法,new出来的对象都有say的方法。 }; Person.prototype.eat = function () { console.log(this.name + "eat something..."); }; //为Person定义了一个原型方法eat,该方法为公共方法。每一个通过new Person 实例出来的对象都共享同一个eat方法。 Person.staticMethod = function () { console.log("this is static method"); }; //定义静态方法,该方法目的在于不用new Person 就能调用该方法。我们把不用实例化就能调用的方法叫做静态方法。 </source> ===在Js中使用new 关键字调用一个函数的问题=== <source lang="javascript"> var zhangsan = new Person(); // 实际上内部是这样的: var zhangsan = {}; zhangsan.__proto__ = Person.prototype; Person.call(zhangsan); </source> 上面三句代码的说明: # 声明了一个zhangsan的空对象 # 将Person的prototype赋值给zhangsan的proto属性。关于对象的prototype和proto概念如下:prototype是函数的一个属性(每个函数都有一个prototype属性),这个属性是一个指针,指向一个对象。它是显示修改对象的原型的属性。proto是一个对象拥有的内置属性(每个对象都有一个proto属性),是JS内部使用寻找原型链的属性。这就是为什么zhangsan可以调用到Person原型(Person.prototype)方法的原因。 # 调用Person函数,并且把zhangsan当成是this传入函数中,这就是为什么zhangsan可以调用Person函数定义的this.属性或this.方法的原因 ===构造函数返回值得问题=== 任意一个函数都是有返回值得,如果我们不明确的写出返回值 函数默认返回的是undefined.构造函数也是一样。 <source lang="javascript"> var f = function () { this.name = "f_name"; this.say = function () { console.log("say"); }; console.log("in f"); }; console.log(f()); //我们用chrome执行上面代码获取的结果为: //in f //undefined var fo = new f(); console.log(fo); //返回的是:执行完fo.__proto__=f.prototype绑定关系和f.call(fo)调用的fo对象。 </source> 如果我的构造函数有明确的返回值呢? <source lang="javascript"> var f=function(){ this.name="f_name"; this.say=function(){ console.log("say"); } return '123'; } //非 new调用: f(); //返回"123"的字符串,这相当于就是调用的一个普通函数 //new 调用 new f(); //返回值同返回undefined时相同的{__proto__:f,name:"f_name",say:function()arguments: null,caller: null,length: 0,name: "",prototype....} </source> 如果我们的返回值是一个对象呢? <source lang="javascript"> var f = function () { this.name = "f_name"; this.say = function () { console.log("say"); }; return {"age": 25} }; //非 new调用: console.log(f()); //返回{"age":25}的字符串,这相当于就是调用的一个普通函数 //new 调用 console.log(new f()); //返回值是:{age: 25} </source> 也就是说,如果我们的函数明确返回一个对象,则无论是否使用new关键字调用,都获取的是返回的这个对象,这也是很多使用该方法构建模块化的方法和原理。 ===构造函数的调用=== 结合上面的例子和原理的理解,下面做一些基本的测试。 <source lang="javascript"> Person().staticMethod()//报错,因为Person()是一般的函数调用,因为Person没有明确的返回值所以默认返回为undefined,所以 调用代码实际上是undefined.方法,所以error了 Person.staticMethod()//打印结果为:this is static method,此次调用的是静态方法,如何定义的就如何调用 Person.prototype.eat()//调用原型链中的方法,但eat中的this,指定的是window 所以打印结果为:undefined eat something... var zhangsan = new Person() //先在zhangsan对象中找是否有eat方法发现没有, //则通过__proto__去找,上面我们提到过, //new 关键字调用会将: zhangsan,__proto__=Person.prototype, //所以就会去Person.prototype找eat方法,找到了调用, //而关于this.name获取到值原因同样是因为new 关键字的 Person.call(zhangsan)的执行操作, //将Person中的this相关的内容都进行了"copy",其实就是this复制到了zhangsan对象中, //关于这点我们前面已验证过了.所以zhangsan.name是能找到值的 //输出结果就成了:double eat something... zhangsan.eat()//double eat something... zhangsan.name//同上 </source> ==function, new function, new Function之间的区别区别分析== 只要 new 表达式之后的 constructor 返回(return)一个引用对象(数组,对象,函数等),都将覆盖new创建的匿名对象,如果返回(return)一个原始类型(无 return 时其实为 return 原始类型 undefined),那么就返回 new 创建的匿名对象。 <source lang="javascript"> var yx01 = new function () { return "圆心" }; console.log(yx01); //我们运行代码,将返回显示“[object object] ”,此时该代码等价于: //function 匿名类(){ // return "圆心"; //} var yx01 = new function () { return new String }; console.log(yx01); var yx02 = function () { return "圆心" }(); console.log(yx02); </source> 变量 doAdd 被定义为函数,然后 alsodoAdd 被声明为指向同一个函数的指针。用这两个变量都可以执行该函数的代码,并输出相同的结果 - "20"。 Function 对象也有与所有对象共享的 valueOf() 方法和 toString() 方法。这两个方法返回的都是函数的源代码,在调试时尤其有用。 <source lang="javascript"> var doAdd = new Function("iNum", "console.log(iNum + 10)"); var alsodoAdd = doAdd; doAdd(10); //输出 "20" alsodoAdd(10); //输出 "20" console.log(doAdd.valueOf()); console.log(doAdd.toString()); </source> 函数 doAdd() 定义了一个参数,因此它的 length 是 1;sayHi() 没有定义参数,所以 length 是 0。 <source lang="javascript"> function doAdd(iNum) { alert(iNum + 10); } function sayHi() { alert("Hi"); } console.log(doAdd.length); //输出 "1" console.log(sayHi.length); //输出 "0" // 形式一 var foo01 = function () //or fun01 = function() { var temp = 100; this.temp = 200; return temp + this.temp; } console.log(typeof(foo01)); console.log(foo01()); // 形式二 var foo02 = new function () { var temp = 100; this.temp = 200; return temp + this.temp; }; console.log(typeof(foo02)); console.log(foo02.constructor()); // 形式三 var foo3 = new Function('var temp = 100; this.temp = 200; return temp + this.temp;'); console.log(typeof(foo3)); console.log(foo3()); // 形式四:这个方式是不常使用的,效果和方法三一样,不过不清楚不用new来生成有没有什么副作用, // 这也体现了JavaScript一个最大的特性:灵活!能省就省。 var foo4 = Function('var temp = 100; this.temp = 200; return temp + this.temp;'); console.log(typeof(foo4)); console.log(foo4()); </source> ==JavaScript中以function定义的函数和以new Function定义的函数不等价?== 首先给一段代码: <source lang="javascript"> window.local = 'hi'; (function () { var local = 1; console.log(typeof local); //number Function("console.log(typeof local);")(); //string }()); </source> 看完这段代码,相信应该有些模糊的猜测了。下面说结论: # `Function(arg1, arg2, ..., body)` 等价于 `new Function(arg1, arg2, ..., body)`。 # 对 `function fn(){}` 和 `var fn = function(){}` 而言,以当前的 LexicalEnvironment 作为 scope 传给函数。 # 对 `new Function(arg1, arg2, ..., body)` 而言,以 Global Environment,浏览器上就是 window 为 scope。 所以你列出的那些例子中,`(new) Function("console.log(typeof local);")();` 中对local取得是 window.local, 这个是 undefined。 ==最详尽的 JS 原型与原型链终极详解,没有「可能是」。== https://www.jianshu.com/p/dee9f8b14771 ===总论=== 什么是原型、原型链? 它们有什么特点? 它们能做什么? 怎么确定它们的关系? ===一. 普通对象与函数对象=== 凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。 <source lang="javascript"> Person.prototype.constructor == Person; person1.__proto__ == Person.prototype; person1.constructor == Person; </source> JavaScript 是基于原型的。简单来说,就是当我们创建一个函数的时候,系统就会自动分配一个 prototype属性,可以用来存储可以让所有实例共享的属性和方法。 <source lang="javascript"> function Person() { } var p = new Person(); p.__proto__ === Person.prototype // true Person.prototype.constructor === Person // true </source> * 每一个构造函数都拥有一个 prototype 属性,这个属性指向一个对象,也就是原型对象 * 原型对象默认拥有一个 constructor 属性,指向指向它的那个构造函数 * 每个对象都拥有一个隐藏的属性 __proto__,指向它的原型对象 原型特点 * 实例可以共享原型上面的属性和方法。 * 实例自身的属性会屏蔽原型上面的同名属性,实例上面没有的属性会去原型上面找。 原型重写 <source lang="javascript"> function Person(){} var p = new Person(); Person.prototype = { name: 'tt', age: 18 } Person.prototype.constructor === Person // false p.name // undefined </source> * 在已经创建了实例的情况下重写原型,会切断现有实例与新原型之间的联系。 * 重写原型对象,会导致原型对象的 constructor 属性指向 Object ,导致原型链关系混乱,所以我们应该在重写原型对象的时候指定 constructor( instanceof 仍然会返回正确的值)。 <source lang="javascript"> Person.prototype = { constructor: Person } </source> 注意:以这种方式重设 constructor 属性会导致它的 Enumerable 特性被设置成 true(默认为false)。 ===二. 构造函数=== 我们先复习一下构造函数的知识: <source lang="javascript"> 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, 'Software Engineer'); var person2 = new Person('Mick', 23, 'Doctor'); </source> 上面的例子中 person1 和 person2 都是 Person 的实例。这两个实例都有一个 constructor (构造函数)属性,该属性(是一个指针)指向 Person。 即: <source lang="javascript"> console.log(person1.constructor == Person); //true console.log(person2.constructor == Person); //true </source> 我们要记住两个概念(构造函数,实例):person1 和 person2 都是 构造函数 Person 的实例 一个公式:实例的构造函数属性(constructor)指向构造函数。 ===三. 原型对象=== 每个对象都有 __proto__ 属性,但只有函数对象才有 prototype 属性。 原型对象(Person.prototype)是 构造函数(Person)的一个实例。 原型对象,顾名思义,它就是一个普通对象(废话 = =!)。从现在开始你要牢牢记住原型对象就是 Person.prototype。 在默认情况下,所有的原型对象都会自动获得一个 constructor(构造函数)属性,这个属性(是一个指针)指向 prototype 属性所在的函数(Person)。 上面这句话有点拗口,我们「翻译」一下:A 有一个默认的 constructor 属性,这个属性是一个指针,指向 Person。即: <source lang="javascript"> Person.prototype.constructor == Person </source> 原型对象其实就是普通对象(但 Function.prototype 除外,它是函数对象,但它很特殊,他没有prototype属性(前面说道函数对象都有prototype属性)。看下面的例子: <source lang="javascript"> function Person(){}; console.log(Person.prototype) //Person{} console.log(typeof Person.prototype) //Object console.log(typeof Function.prototype) // Function,这个特殊 console.log(typeof Object.prototype) // Object console.log(typeof Function.prototype.prototype) //undefined </source> Function.prototype 为什么是函数对象呢? <source lang="javascript"> var A = new Function (); Function.prototype = A; </source> 上文提到凡是通过 new Function( ) 产生的对象都是函数对象。因为 A 是函数对象,所以Function.prototype 是函数对象。 那原型对象是用来做什么的呢?主要作用是用于继承。举个例子: <source lang="javascript"> var Person = function (name) { this.name = name; // tip: 当函数执行时这个 this 指的是谁? }; Person.prototype.getName = function () { return this.name; // tip: 当函数执行时这个 this 指的是谁? }; var person1 = new Person('Mick'); person1.getName(); //Mick </source> 从这个例子可以看出,通过给 Person.prototype 设置了一个函数对象的属性,那有 Person 的实例(person1)出来的普通对象就继承了这个属性。具体是怎么实现的继承,就要讲到下面的原型链了。 小问题,上面两个 this 都指向谁? <source lang="javascript"> var person1 = new person('Mick'); person1.name = 'Mick'; // 此时 person1 已经有 name 这个属性了 person1.getName(); //Mick </source> 故两次 this 在函数执行时都指向 person1。 null 是一个独立的数据类型,为什么typeof(null)的值是"object"? # null不是一个空引用, 而是一个原始值, 参考ECMAScript5.1中文版** 4.3.11节; 它只是期望此处将引用一个对象, 注意是"期望", 参考 null - JavaScript**。 # typeof null结果是object, 这是个历史遗留bug, 参考 typeof - JavaScript**。 # 在ECMA6中, 曾经有提案为历史平凡, 将type null的值纠正为null, 但最后提案被拒了. 理由是历史遗留代码太多, 不想得罪人, 不如继续将错就错当和事老。 ===四. __proto__=== JS 在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__ 的内置属性,用于指向创建它的构造函数的原型对象。 对象 person1 有一个 __proto__属性,创建它的构造函数是 Person,构造函数的原型对象是 Person.prototype ,所以: <source lang="javascript"> Person.prototype.constructor == Person; person1.__proto__ == Person.prototype; person1.constructor == Person; </source> 不过,要明确的真正重要的一点就是,这个连接存在于实例(person1)与构造函数(Person)的原型对象(Person.prototype)之间,而不是存在于实例(person1)与构造函数(Person)之间。 ===五. 构造器=== 熟悉 Javascript 的童鞋都知道,我们可以这样创建一个对象: <source lang="javascript"> var obj = {} //它等同于下面这样: var obj = new Object() //obj 是构造函数(Object)的一个实例。所以: obj.constructor === Object obj.__proto__ === Object.prototype </source> 新对象 obj 是使用 new 操作符后跟一个构造函数来创建的。构造函数(Object)本身就是一个函数(就是上面说的函数对象),它和上面的构造函数 Person 差不多。只不过该函数是出于创建新对象的目的而定义的。所以不要被 Object 吓倒。 同理,可以创建对象的构造器不仅仅有 Object,也可以是 Array,Date,Function等。 所以我们也可以构造函数来创建 Array、 Date、Function。 ===六. 原型链=== JavaScript 中所有的对象都是由它的原型对象继承而来。而原型对象自身也是一个对象,它也有自己的原型对象,这样层层上溯,就形成了一个类似链表的结构,这就是原型链。 * 所有原型链的终点都是 Object 函数的 prototype 属性。 * Objec.prototype 指向的原型对象同样拥有原型,不过它的原型是 null ,而 null 则没有原型。 小测试来检验一下你理解的怎么样: # person1.__proto__ 是什么? # Person.__proto__ 是什么? # Person.prototype.__proto__ 是什么? # Object.__proto__ 是什么? # Object.prototype.__proto__ 是什么? 答案: 第一题: 因为 person1.__proto__ === person1 的构造函数.prototype 因为 person1的构造函数 === Person 所以 person1.__proto__ === Person.prototype 第二题: 因为 Person.__proto__ === Person的构造函数.prototype 因为 Person的构造函数 === Function 所以 Person.__proto__ === Function.prototype 第三题: Person.prototype 是一个普通对象,我们无需关注它有哪些属性,只要记住它是一个普通对象。 因为一个普通对象的构造函数 === Object 所以 Person.prototype.__proto__ === Object.prototype 第四题,参照第二题,因为 Person 和 Object 一样都是构造函数 第五题: Object.prototype 对象也有proto属性,但它比较特殊,为 null 。因为 null 处于原型链的顶端,这个只能记住。 Object.prototype.__proto__ === null ===七. 函数对象=== 所有函数对象的proto都指向Function.prototype,它是一个空函数(Empty function) <source lang="javascript"> Number.__proto__ === Function.prototype // true Number.constructor == Function //true Boolean.__proto__ === Function.prototype // true Boolean.constructor == Function //true String.__proto__ === Function.prototype // true String.constructor == Function //true // 所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身 Object.__proto__ === Function.prototype // true Object.constructor == Function // true // 所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身 Function.__proto__ === Function.prototype // true Function.constructor == Function //true Array.__proto__ === Function.prototype // true Array.constructor == Function //true RegExp.__proto__ === Function.prototype // true RegExp.constructor == Function //true Error.__proto__ === Function.prototype // true Error.constructor == Function //true Date.__proto__ === Function.prototype // true Date.constructor == Function //true </source> JavaScript中有内置(build-in)构造器/对象共计12个(ES5中新加了JSON),这里列举了可访问的8个构造器。剩下如Global不能直接访问,Arguments仅在函数调用时由JS引擎创建,Math,JSON是以对象形式存在的,无需new。它们的proto是Object.prototype。如下 <source lang="javascript"> Math.__proto__ === Object.prototype // true Math.construrctor == Object // true JSON.__proto__ === Object.prototype // true JSON.construrctor == Object //true </source> 上面说的函数对象当然包括自定义的。如下 <source lang="javascript"> // 函数声明 function Person() {} // 函数表达式 var Perosn = function() {} console.log(Person.__proto__ === Function.prototype) // true console.log(Man.__proto__ === Function.prototype) // true </source> 这说明什么呢? 所有的构造器都来自于 Function.prototype,甚至包括根构造器Object及Function自身。所有构造器都继承了·Function.prototype·的属性及方法。如length、call、apply、bind (你应该明白第一句话,第二句话我们下一节继续说,先挖个坑:)) Function.prototype也是唯一一个typeof XXX.prototype为 function的prototype。其它的构造器的prototype都是一个对象(原因第三节里已经解释过了)。如下(又复习了一遍): <source lang="javascript"> console.log(typeof Function.prototype) // function console.log(typeof Object.prototype) // object console.log(typeof Number.prototype) // object console.log(typeof Boolean.prototype) // object console.log(typeof String.prototype) // object console.log(typeof Array.prototype) // object console.log(typeof RegExp.prototype) // object console.log(typeof Error.prototype) // object console.log(typeof Date.prototype) // object console.log(typeof Object.prototype) // object </source> 噢,上面还提到它是一个空的函数,console.log(Function.prototype) 下看看(留意,下一节会再说一下这个) 知道了所有构造器(含内置及自定义)的__proto__都是Function.prototype,那Function.prototype的__proto__是谁呢? 相信都听说过JavaScript中函数也是一等公民,那从哪能体现呢?如下 <source lang="javascript"> console.log(Function.prototype.__proto__ === Object.prototype) // true </source> 这说明所有的构造器也都是一个普通 JS 对象,可以给构造器添加/删除属性等。同时它也继承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。(你也应该明白第一句话,第二句话我们下一节继续说,不用挖坑了,还是刚才那个坑;)) 最后Object.prototype的proto是谁? <source lang="javascript"> Object.prototype.__proto__ === null // true </source> 已经到顶了,为null。(读到现在,再回过头看第五章,能明白吗?) ===八. Prototype=== 在 ECMAScript 核心所定义的全部属性中,最耐人寻味的就要数 prototype 属性了。对于 ECMAScript 中的引用类型而言,prototype 是保存着它们所有实例方法的真正所在。换句话所说,诸如 toString()和 valuseOf() 等方法实际上都保存在 prototype 名下,只不过是通过各自对象的实例访问罢了。——《JavaScript 高级程序设计》第三版 P116 我们知道 JS 内置了一些方法供我们使用,比如: * 对象可以用 constructor/toString()/valueOf() 等方法; * 数组可以用 map()/filter()/reducer() 等方法; * 数字可用用 parseInt()/parseFloat()等方法; 当我们创建一个函数时: <source lang="javascript"> var Person = new Object() </source> Person 是 Object 的实例,所以 Person 继承了Object 的原型对象Object.prototype上所有的方法。 当我们创建一个数组时: <source lang="javascript"> var num = new Array() </source> num 是 Array 的实例,所以 num 继承了Array 的原型对象Array.prototype上所有的方法。 我们可以用一个 ES5 提供的新方法:Object.getOwnPropertyNames获取所有(包括不可枚举的属性)的属性名不包括 prototy 中的属性,返回一个数组: <source lang="javascript"> var arrayAllKeys = Array.prototype; // [] 空数组 // 只得到 arrayAllKeys 这个对象里所有的属性名(不会去找 arrayAllKeys.prototype 中的属性) console.log(Object.getOwnPropertyNames(arrayAllKeys)); /* 输出: ["length", "constructor", "toString", "toLocaleString", "join", "pop", "push", "concat", "reverse", "shift", "unshift", "slice", "splice", "sort", "filter", "forEach", "some", "every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight", "entries", "keys", "copyWithin", "find", "findIndex", "fill"] */ </source> 细心的你肯定发现了Object.getOwnPropertyNames(arrayAllKeys) 输出的数组里并没有 constructor/hasOwnPrototype等对象的方法(你肯定没发现)。 因为Array.prototype 虽然没这些方法,但是它有原型对象(__proto__): <source lang="javascript"> // 上面我们说了 Object.prototype 就是一个普通对象。 Array.prototype.__proto__ == Object.prototype </source> 所以 Array.prototype 继承了对象的所有方法,当你用num.hasOwnPrototype()时,JS 会先查一下它的构造函数 (Array) 的原型对象 Array.prototype 有没有有hasOwnPrototype()方法,没查到的话继续查一下 Array.prototype 的原型对象 Array.prototype.__proto__有没有这个方法。 当我们创建一个函数时: <source lang="javascript"> var f = new Function("x","return x*x;"); //当然你也可以这么创建 f = function(x){ return x*x } console.log(f.arguments) // arguments 方法从哪里来的? console.log(f.call(window)) // call 方法从哪里来的? console.log(Function.prototype) // function() {} (一个空的函数) console.log(Object.getOwnPropertyNames(Function.prototype)); /* 输出 ["length", "name", "arguments", "caller", "constructor", "bind", "toString", "call", "apply"] */ </source> 我们再复习第八小节这句话: 所有函数对象proto都指向 Function.prototype,它是一个空函数(Empty function) 还有,我建议你可以再复习下为什么: Function.prototype 是唯一一个typeof XXX.prototype为 “function”的prototype 我猜你肯定忘了。 ===九. 复习一下=== 先看看 JS 内置构造器: <source lang="javascript"> var obj = {name: 'jack'} var arr = [1,2,3] var reg = /hello/g var date = new Date var err = new Error('exception') console.log(obj.__proto__ === Object.prototype) // true console.log(arr.__proto__ === Array.prototype) // true console.log(reg.__proto__ === RegExp.prototype) // true console.log(date.__proto__ === Date.prototype) // true console.log(err.__proto__ === Error.prototype) // true </source> 再看看自定义的构造器,这里定义了一个 Person: <source lang="javascript"> function Person(name) { this.name = name; } var p = new Person('jack') console.log(p.__proto__ === Person.prototype) // true </source> p 是 Person 的实例对象,p 的内部原型总是指向其构造器 Person 的原型对象 prototype。每个对象都有一个 constructor 属性,可以获取它的构造器,因此以下打印结果也是恒等的: <source lang="javascript"> function Person(name) { this.name = name } var p = new Person('jack') console.log(p.__proto__ === p.constructor.prototype) // true </source> 上面的Person没有给其原型添加属性或方法,这里给其原型添加一个getName方法: <source lang="javascript"> function Person(name) { this.name = name } // 修改原型 Person.prototype.getName = function() {} var p = new Person('jack') console.log(p.__proto__ === Person.prototype) // true console.log(p.__proto__ === p.constructor.prototype) // true </source> 可以看到p.__proto__与Person.prototype,p.constructor.prototype都是恒等的,即都指向同一个对象。如果换一种方式设置原型,结果就有些不同了: <source lang="javascript"> function Person(name) { this.name = name } // 重写原型 Person.prototype = { getName: function() {} } var p = new Person('jack') console.log(p.__proto__ === Person.prototype) // true console.log(p.__proto__ === p.constructor.prototype) // false </source> 这里直接重写了 Person.prototype(注意:上一个示例是修改原型)。输出结果可以看出p.__proto__仍然指向的是Person.prototype,而不是p.constructor.prototype。 这也很好理解,给Person.prototype赋值的是一个对象直接量{getName: function(){}},使用对象直接量方式定义的对象其构造器(constructor)指向的是根构造器Object,Object.prototype是一个空对象{},{}自然与{getName: function(){}}不等。如下: <source lang="javascript"> var p = {} console.log(Object.prototype) // 为一个空的对象{} console.log(p.constructor === Object) // 对象直接量方式定义的对象其constructor为Object console.log(p.constructor.prototype === Object.prototype) // 为true,不解释(๑ˇ3ˇ๑) </source> ===十. 原型链(再复习一下:)=== 下面这个例子你应该能明白了! <source lang="javascript"> function Person(){} var person1 = new Person(); console.log(person1.__proto__ === Person.prototype); // true console.log(Person.prototype.__proto__ === Object.prototype) //true console.log(Object.prototype.__proto__) //null Person.__proto__ == Function.prototype; //true console.log(Function.prototype)// function(){} (空函数) var num = new Array() console.log(num.__proto__ == Array.prototype) // true console.log( Array.prototype.__proto__ == Object.prototype) // true console.log(Array.prototype) // [] (空数组) console.log(Object.prototype.__proto__) //null console.log(Array.__proto__ == Function.prototype)// true </source> 疑点解惑: <source lang="javascript"> Object.__proto__ === Function.prototype // true </source> Object 是函数对象,是通过new Function()创建的,所以Object.__proto__指向Function.prototype。(参照第八小节:「所有函数对象的__proto__都指向Function.prototype」) <source lang="javascript"> Function.__proto__ === Function.prototype // true </source> Function 也是对象函数,也是通过new Function()创建,所以Function.__proto__指向Function.prototype。 自己是由自己创建的,好像不符合逻辑,但仔细想想,现实世界也有些类似,你是怎么来的,你妈生的,你妈怎么来的,你姥姥生的,……类人猿进化来的,那类人猿从哪来,一直追溯下去……,就是无,(NULL生万物) 正如《道德经》里所说“无,名天地之始”。 <source lang="javascript"> Function.prototype.__proto__ === Object.prototype //true </source> 其实这一点我也有点困惑,不过也可以试着解释一下。 Function.prototype是个函数对象,理论上他的__proto__应该指向 Function.prototype,就是他自己,自己指向自己,没有意义。 JS一直强调万物皆对象,函数对象也是对象,给他认个祖宗,指向Object.prototype。Object.prototype.__proto__ === null,保证原型链能够正常结束。 ===十一 总结=== 原型和原型链是JS实现继承的一种模型。原型链的形成是真正是靠__proto__ 而非prototype。 要深入理解这句话,我们再举个例子,看看前面你真的理解了吗? <source lang="javascript"> var animal = function () { }; var dog = function () { }; animal.price = 2000; dog.prototype = animal; var tidy = new dog(); console.log(dog.price); //undefined console.log(tidy.price); // 2000 </source> 这里解释一下: <source lang="javascript"> var dog = function () { }; dog.prototype.price = 2000; var tidy = new dog(); console.log(tidy.price); // 2000 console.log(dog.price); //undefined var dog = function () { }; var tidy = new dog(); tidy.price = 2000; console.log(dog.price); //undefined </source> 这个明白吧?想一想我们上面说过这句话: 实例(tidy)和 原型对象(dog.prototype)存在一个连接。不过,要明确的真正重要的一点就是,这个连接存在于实例(tidy)与构造函数的原型对象(dog.prototype)之间,而不是存在于实例(tidy)与构造函数(dog)之间。 聪明的你肯定想通了吧 :) ===class类=== ES6 提供了 Class(类) 这个概念,作为对象的模板,通过 class 关键字,可以定义类。 ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。 <source lang="javascript"> class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } } // 可以这么改写 function Point(x, y) { this.x = x; this.y = y; } Point.prototype.toString = function () { return '(' + this.x + ', ' + this.y + ')'; }; </source> class 里面定义的方法,其实都是定义在构造函数的原型上面实现实例共享,属性定义在构造函数中,所以 ES6 中的类完全可以看作构造函数的另一种写法 除去 class 类中的一些行为可能与 ES5 存在一些不同,本质上都是通过原型、原型链去定义方法、实现共享。所以,还是文章开始那句话 JavaScript是基于原型的。 ===关系判断=== instanceof 最常用的确定原型指向关系的关键字,检测的是原型,但是只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型 <source lang="javascript"> function Person(){} var p = new Person(); p instanceof Person // true p instanceof Object // true </source> hasOwnProperty 通过使用 hasOwnProperty 可以确定访问的属性是来自于实例还是原型对象 <source lang="javascript"> function Person() {} Person.prototype = { name: 'tt' } var p = new Person(); p.age = 15; p.hasOwnProperty('age') // true p.hasOwnProperty('name') // false </source> ===原型链的问题=== 由于原型链的存在,我们可以让很多实例去共享原型上面的方法和属性,方便了我们的很多操作。但是原型链并非是十分完美的: <source lang="javascript"> function Person(){} Person.prototype.arr = [1, 2, 3, 4]; var person1 = new Person(); var person2 = new Person(); person1.arr.push(5) person2.arr // [1, 2, 3, 4, 5] </source> 引用类型,变量保存的就是一个内存中的一个指针。所以,当原型上面的属性是一个引用类型的值时,我们通过其中某一个实例对原型属性的更改,结果会反映在所有实例上面,这也是原型共享属性造成的最大问题。 另一个问题就是我们在创建子类型(比如上面的 p)时,没有办法向超类型( Person )的构造函数中传递参数。 ===后记=== 鉴于原型的特点和存在的问题,所以我们在实际开发中一般不会单独使用原型链。一般会使用构造函数和原型相配合的模式,当然这也就牵扯出了 JavaScript 中另一个有意思的领域:继承。 ==js正则表达式== <source lang="javascript"> var currency = /((^([1-9]\d*))|^0)(\.\d{1,2})?$|(^0\.\d{1,2}$)/; var people = /^([1-9]\d*)?$/; </source> ==js浮点运算bug的解决办法== 使用big.js。 ==jQuery中.bind() .live() .delegate() .on()的区别== <source lang="javascript"> //为每个匹配元素的特定事件绑定事件处理函数 bind(type,[data],fn) $("a").bind("click",function(){alert("ok");}); //给所有匹配的元素附加一个事件处理函数,即使这个元素是以后再添加进来的 live(type,[data],fn) $("a").live("click",function(){alert("ok");}); //指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数 delegate(selector,[type],[data],fn) $("#container").delegate("a","click",function(){alert("ok");}) //在选择元素上绑定一个或多个事件的事件处理函数 on(events,[selector],[data],fn) </source> 差别 * .bind()是直接绑定在元素上 * .live()则是通过冒泡的方式来绑定到元素上的。更适合列表类型的,绑定到document DOM节点上。和.bind()的优势是支持动态数据。 * .delegate()则是更精确的小范围使用事件代理,性能优于.live() * .on()则是最新的1.9版本整合了之前的三种方式的新事件绑定机制 ==js 判断微信浏览器== <source lang="javascript"> //JS function isWeiXin(){ var ua = window.navigator.userAgent.toLowerCase(); if(ua.match(/MicroMessenger/i) == 'micromessenger'){ return true; }else{ return false; } } </source> <source lang="php"> //PHP function is_weixin(){ if ( strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false ) { return true; } return false; } </source> ==script标签的async属性== 一般的script标签(不带async等属性)加载时会阻塞浏览器,也就是说,浏览器在下载或执行该js代码块时,后面的标签不会被解析,例如在head中添加一个script,但这个script下载时网络不稳定,很长时间没有下载完成对应的js文件,那么浏览器此时一直等待这个js文件下载,此时页面不会被渲染,用户看到的就是白屏(网页文件已下载好,但浏览器不解析) 而使用async属性,浏览器会下载js文件,同时继续对后面的内容进行渲染 通常如果js不需要改变DOM结构时可以使用async进行异步加载(比如一些统计代码可以异步加载,因为此代码与页面执行逻辑无关,不会改变DOM结构) ==IE8中trim方法报错的问题== <source lang="javascript"> //IE8下没有 str.trim() //替代方案 Ext.string.trim(str) //Extjs用法 $.trim(str) //jquery用法 </source> ==JS基础== <div id="indexContent"> [[字符串]] [[数组]] </div> [[window.location.hash属性介绍]] [http://www.ecma-international.org/memento/history.htm History of Ecma] [http://www.cnblogs.com/fumj/archive/2012/12/01/2797588.html javascript避免数字计算精度误差的方法之一] [[如何判断Javascript对象是否存在]] ==JS中级== <div id="indexContent"> [[jsoop|OOP]] </div> [[再谈javascript面向对象编程]] * [http://www.cnblogs.com/rubylouvre/archive/2009/07/24/1530074.html javascript的闭包 - 司徒正美] * [http://www.cnblogs.com/zhjjNo1/archive/2011/02/12/1951905.html js闭包] * [http://blog.csdn.net/adwu73/article/details/7229564 JavaScript对象系统深入剖析-4.Scope和Closure] * [http://hi.baidu.com/hu5210898/blog/item/0aa4fb476bd3ed036a63e52c.html js原型理解] * [http://hi.baidu.com/52weber/blog/item/b2b39d360a2fc30a91ef3986.html 原型和继承] * [http://www.ibm.com/developerworks/cn/web/wa-jsdom/index.html JavaScript 和文档对象模型(DOM)] * [http://blog.csdn.net/vincent17113/article/details/5523539 那些相见恨晚的 JavaScript 技巧] * [http://www.zhangxinxu.com/wordpress/?p=600 回流与重绘:CSS性能让JavaScript变慢?] * [http://www.blogjava.net/BearRui/archive/2010/05/10/web_performance_repaint_relow.html 高性能WEB开发(8) - 页面呈现、重绘、回流] * [http://www.cnblogs.com/sxwgf/archive/2011/11/14/2248425.html Javascript中的陷阱大集合] * [http://www.itivy.com/ivy/archive/2011/11/13/my-javascript-gotchas.html Javascript中的陷阱大集合] * [http://blog.csdn.net/a_heng/article/details/4135345 js数组的操作] * [http://dxz506.blog.163.com/blog/static/103254696201091525048328/ JS刷新当前页面] * [http://blog.csdn.net/shan9liang/article/details/7206440 JS操作DOM节点实现网页更新] * [http://www.zhangxinxu.com/wordpress/2009/10/%e7%bf%bb%e8%af%91%ef%bc%9a%e8%ae%a9%e7%bd%91%e7%bb%9c%e6%9b%b4%e5%bf%ab%e4%b8%80%e4%ba%9b%e2%80%94%e2%80%94%e6%9c%80%e5%b0%8f%e5%8c%96%e6%b5%8f%e8%a7%88%e5%99%a8%e4%b8%ad%e7%9a%84%e5%9b%9e%e6%b5%81r/ 翻译:让网络更快一些——最小化浏览器中的回流(reflow) ? 张鑫旭-鑫空间-鑫生活] * [http://developer.51cto.com/art/201106/267559.htm 快速判断JavaScript对象是否存在的十个方法] * [http://developer.51cto.com/art/201106/267011.htm JavaScript重构深入剖析] ==JS高级== <div id="indexContent"> </div> * [http://kb.cnblogs.com/page/112185/ 反向Ajax,第1部分:Comet介绍] * [http://www.ibm.com/developerworks/cn/web/wa-webappperformance/index.html 提升 web 应用程序的性能] * [http://www.ibm.com/developerworks/cn/web/1107_zhouxiang_tunejs/index.html 提高 web 应用性能之 JavaScript 性能调优] * [http://www.ibm.com/developerworks/cn/web/1011_shaoyu_web20bank2/index.html 基于 Web 2.0 技术的网上银行前端架构及开发,第 2 部分: 前端创新型设计] * [http://www.ibm.com/developerworks/cn/web/0912_chenxm_web20bank/index.html 基于 Web 2.0 技术的网上银行前端架构及开发,第 1 部分: 基本元素和架构] * [http://developer.51cto.com/art/201106/268387.htm Web开发前沿技术探索与实战] * [http://www.ibm.com/developerworks/cn/web/wa-improve/index.html 让您的 web 应用程序飞起来] * [http://developer.51cto.com/art/201106/270802.htm 一位反JavaScript主义者的觉醒] * [http://developer.51cto.com/art/201105/260992.htm 15款超棒的JavaScript开发工具推荐] * [http://www.cnblogs.com/muguaworld/archive/2011/11/27/2264741.html 如何快速成为javascript高手的思考] * [http://www.ibm.com/developerworks/cn/java/j-lo-javawebhiperf1/index.html Java Web 高性能开发,第 1 部分: 前端的高性能] * [http://developer.51cto.com/art/201203/323057.htm 性能优化:如何更快速加载你的JavaScript页面] * [http://www.cnblogs.com/hkncd/archive/2012/03/26/2417315.html 从今天开始,调试脚本,远离alert] * [http://developer.51cto.com/art/201002/185161.htm JavaScript最让人费解的十件事] ==[[javascript代码片段]]== ==杂项== [http://www.cnblogs.com/ShepherdIsland/archive/2012/05/22/Fiddler_AutoResponder_REGEX.html Fiddler自动响应AutoResponder正则匹配] 用正则批量替换 regex:http://cc-t\.ied\.com/(.+)\.js http://localhost/$1.js [[JS模板引擎jSmart]] [[写一段最短的代码,用上js所有关键字]] [[实用Javascript代码高亮脚本]] [[JS正则表达式]] [[精通JavaScript需要注意的细节:变量]] [[确保链接不依赖于javascript]] [[javascript 框架功能大剖析]] [[12种JavaScript MVC框架之比较]] [[JavaScript框架]] [[ArtTemplate高性能JavaScript模板引擎]] [[JavaScript开发者值得收藏的 7 个资源]] [[一个Web前端攻城狮的收藏夹]] [[前端招聘与前端卖身的困境]] [[基于Web的打印方案比较分析]] [[浏览器的两种模式quirks 和strict]] ==zebra-dialog== http://sourceforge.net/projects/zebra-dialog/ http://stefangabos.ro/jquery/zebra-dialog/#how-to-use ==使用Chrome Console调试代码== * [https://developers.google.com/chrome-developer-tools/docs/console Using the Console] * [https://developers.google.com/chrome-developer-tools/docs/console-api Console API Reference] ==javascript代码风格== [http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml google javascript styleguide] ==webstorm== ;JSLint was used before it was defined As Quentin says, there's a /*global*/ directive.Here is an example (put this at the top of the file): <source lang="javascript"> /*global var1,var2,var3,var4,var5*/ </source> ;webstorm 如何设置显示代码的行数 file>setting>editor>appearance>show line nmbers ;注释 Webstorm非常的知心,当你写好函数时候,输入“/**”加回车,会自动生成jsdoc格式的注释。 ;combine this with the previous var statement To avoid this JSLint errors you may 1、Define all variables together var sGreeting = 'hello world', a, b, c; 2、Use JSLint directive Tolerate -> many var statements per function ;JSHint bad line breaking before '+' Relaxing Options -> Supress warnings about unsafe line breaks laxbreak ==webstorm快捷键== F2 向下错误或警告快速定位 Shift+F2 向上错误或警告快速定位 reformat code (cltr+alt+L) structure (alt+7) ctrl+shift+ +/- 展开/折叠 Alt+1 快速打开或隐藏工程面板 Ctrl+X 删除行 Ctrl+D 复制行 shift+enter 重新开始一行(无论光标在哪个位置) Ctrl+Shift+Up/Down 代码向上 Ctrl + shift + j 合并行 Shift + F6 Refactor Rename SHIFT+ALT+INSERT 竖编辑模式 ==JS定时器== 在javascritp中,有两个关于定时器的专用函数,分别为: <source lang="javascript"> //倒计定时器: timer = setTimeout(func_a, delaytime_ms); clearTimeout(timer); //清除已设置的setTimeout对象 //循环定时器: timer = setInterval(func_b, delaytime_ms); clearInterval(timer); //清除已设置的setInterval对象 </source>
返回
JavaScript
。
导航菜单
个人工具
登录
命名空间
页面
讨论
变种
视图
阅读
查看源代码
查看历史
更多
搜索
导航
首页
最近更改
随机页面
帮助
工具
链入页面
相关更改
特殊页面
页面信息