作用域
一、示例
console.log(str); // 输出undefined 因为读取的是解析器预先存储的str,还没有被赋值
var str = 1;
二、示例2
alert(a); // 弹出的是function a(){ alert("2")}
var a = 1;
function a(){
alert("2")
}
预解析会保存a = undefinded,和 a = function a(){alert("2")},
在变量与函数名相同时,输出的结果函数优先级高于变量名
三、示例3
var a = 1;
function a(){
alert("2");
}
// 报错,因为a被定义成变量,typeof a 返回的是number,如果 var a;不能定义值那么a()是成功的
a();
四、示例4
var a = 1;
function fn1(){
alert(a);
// 注意这里因为是使用var声明所以执行数预解析器才会把它单独存储起来,
// 如果将var去掉,a=2改成了赋值这样会改变外部的a的值,下面输出的就是1,2
var a = 2;
}
fn1(); // undefined
console.log(a); // 1
五、示例5
function foo(){
return fn1;
function fn1(){};
var fn1 = 10;
}
var f = foo();
// 输出 function fn1(){}; 因为调用foo函数时,return fn1因为变量还未定义所以 直接调用的函数
alert(f);
六、示例6
var myname = "global"; // 全局变量
function fun() {
alert(myname); // "undefined",如果函数内不在定义myname就会找全局的变量,但函数本身已经定义了,预编译会先将变量定义成undefined
var myname = "local";
alert(myname); // "local"
}
fun();
七、示例7
<script>
window.name = 'globalName';
var getName = function(){
return this.name;
}
getName(); // 'globalName'
</script>
八、示例8
<script>
window.id = 'window';
document.getElementById('divA').onclick = function(){
alert(this.id); // output "divA"
var callback = function(){
return this.id; // output "window"
}
callback(); // 指针指向window
}
</script>
九、示例9
1、var getName;
console.log(getName) // undefined
getName() // Uncaught TypeError: getName is not a function
var getName = function() {
console.log('wscat')
}
2、var getName;
console.log(getName) // function getName() {console.log('oaoafly')}
getName() // oaoafly
function getName() {
console.log('oaoafly')
}
十、bind()
<script>
window.id = 'window';
document.getElementById('divA').onclick = function(){
alert(this.id);
var obj = {
id: 'objId',
callback: function(){
return this.id; // 'divA'
}.bind(window) // 通过bind来将callback内的this指向window
}
console.log(obj.callback()); // 'window'
}
</script>
十一、严格模式下的this
<script>
function fun(){
'use strict'
alert(this); // 返回 'undefined', strict模式下this不会指向全局
}
fun();
</script>
十二、箭头函数下的this指向
let Template = {
test(){
console.log(this); // this指向Template
document.querySelector("#showThis").onclick = () =>{
// 如果非箭头函数this应该指向 #showThis
// 箭头函数不是指向调用者,所以指向了Template
console.log(this);
}
}
}
Template.test();
构造函数
1、函数本身是对象也是构造函数
2、直接挂载到函数下,是对象的属性和方法
function Foo(){};
Foo.username = '111'; // 注意这里Foo的属性不能为name因为被name被函数的名所占用
Foo.getName = function(){ console.log(this.username) };
// 调用
Foo.getName(); // 111
3、在构造函数的内部属性和方法
function Foo() {
this.username = '111'
}
Foo.username = '222';
// 调用
console.log(new Foo().username); // 111
<script>
function Foo() {
getName = function() {
console.log(this);
console.log(1);
}
console.log(this);
return this;
}
Foo.getName = function() { // 这里只是Foo对象的方法,而不是构造函数的方法,
console.log(2);
}
// Foo.prototype.getName = function() {
// console.log(3);
// }
var getName = function() {
console.log(4)
}
function getName() {
console.log(5)
}
Foo.getName(); // 2 Foo.getName=function(){} 是存到Foo下的方法,Foo.getName()可以取到
getName(); // 4 如果一个作用域下有var的变量名与函数名相当,var的作用域提升高于function
Foo().getName(); // 1 因为Foo()被调用,定义中加了return this,Foo指向的是window全局,getName没有var升明,所以为全局,所以相当于window.getName(),Foo中如果不加return this那么就会报错,因为Foo没有链式调用,所以this断了
getName(); // 1 因为上面已经将Foo内的getName()提升成全局,所以会赋盖掉var getName、function getName定义的全局方法
// var ofo = new Foo;
// ofo.getName(); // 3
// Foo既是一个对象也是一个构造函数
new Foo.getName(); // 2 先执行Foo.getName(),因为"."运算符优先于new运算符,所以这时候Foo只是一个对象并不是构造函数的实例,所以会调用对象下的方法
new Foo().getName(); // 1 先执行new Foo()构造函数,然后在构造函数下去找getName方法,Foo构造函数方法没有getName()所以到prototype下去找
new new Foo().getName(); // 1 与上面相同
</script>
对象拷贝并不引用指针
有两种方法,一是使用for...in将一个对象拷贝到另一个对象
另一种方法是使用Object.assign()
let objA = {
name: 'siguang',
age: 30
}
let objB = Object.assign({}, objA);
objB.name = 'lulu'; // lulu
console.log(objA.name); // siguang
对象的深拷贝和浅拷贝
浅拷贝就是对象之间还存引用关系,深拷贝就是两个对象之间没有引用关系
一、浅拷贝
const a = {t: 1, p: 'gg'};
const b = a;
b.t = 3;
console.log(a); // {t: 3, p: 'gg'}
console.log(b); // {t: 3, p: 'gg'}
二 、深拷贝
1、Object.assign() 方法是将两个对象合并,并返回一个新对象
**** 注意assig()只能拷贝一层,多层结构还是浅拷贝 ****
const c = {t: 1, p: 'gg'};
const d = Object.assign({}, c);
d.t = 3;
console.log(c); // {t: 1, p: 'gg'}
console.log(d); // {t: 3, p: 'gg'}
2、Object.create() 将拷贝的内容入到prototype下,对象和数组都适用
对象:
var oA = {
name: 'sg',
age: 33
}
var oB = {};
oB = Object.create(oA);
oB.eat = 'bread';
数组:
var oA = [1,2]
var oB = [];
oB = Object.create(oA);
oB.push(3); // oB.length; 3
3、jQuery.extend()
let oa = {a: 1, b: 2}; let ob = {};
$.extend(ob, oa);
ob.b = 3;
console.log(oa, ob); // oa: {a: 1, b: 2}、 ob: {a: 1, b: 3}
数组的深拷贝
一、concat()方法
var arrA = [1,2,3];
var arrB = arrA.concat();
arrB.push(5,6,7);
console.log(arrA); // [1,2,3]
console.log(arrB); // [1,2,3,5,6,7]
二、slice()方法
var arrA = [1,2,3];
var arrB = arrA.slice();
arrB.push(5,6,7);
console.log(arrA); // [1,2,3]
console.log(arrB); // [1,2,3,5,6,7]
两种方法都是回返一个不带指向的新数组
三、使用扩展运算符...
let a1 = [1, 2, 3];
let a2 = [...a1];
a2.push(4);
console.log(a1); // [1, 2, 3]
console.log(a2); // [1, 2, 3, 4]
对象处理
一、查看是否是一个空对象
// 使用keys来查看对象中所有的kyes并返回一个数组,如果数组为度为0则对象为空
var obj = {};
var Len = Object.keys(obj);
console.log(Len.length);
二、查看对象中属性是否存在
var obj = {
a: 1,
b: 2
}
console.log(obj.c); // undefined
判断数据类型
function isType(data, name){
return Object.prototype.toString.call(data) === `[object ${name}]`
}
isType({}, 'Object'); // true;
数组处理
一、数据去重
1、普通方法
function clearRepeat(arr){
var newArr = [], obj = {};
for(var i=0; i<arr.length; i++){
if(!obj[arr[i]]){
obj[arr[i]] = ''; // 对象属性相同会直接覆盖
newArr.push(key);
}
}
return newArr;
}
let retArray = clearRepeat([3,2,3,4,5,5,2,2,13,3]);
2、使用ES6的set()方法,set方法就是不允许数组内有重复的值
let setValue = new Set([1,2,33,1,22,2,2,4,2,1,2])
console.log(setValue, Object.prototype.toString.call(setValue)); // {size: 5, [1, 2, 33, 22, 4]}, '[Object Set]'
let arr = [...setValue]; // [1, 2, 33, 22, 4] 需要进行解构
http://www.jb51.net/article/46154.htm
二、数组排序
1、使用sort方法
var arr = [6,7,5,8,4,2342342,23,234,2,34];
arr.sort(function(v1, v2){
return v1 - v2 // 正序
})
console.log(arr);
三、返回数组中最大最小值
let arr = [2,1,423,343,5,67,8];
let min = Math.min.apply(null, arr);
let max = Math.max.apply(null, arr);
编写组件并兼容AMD、ES6写法
;(function(root, factory){
// 判断使用的支持定义模块的方式
if(typeof define === 'function' && define.amd){
define(factory)
}
else if(typeof exports === 'object'){
module.exports = factory();
}
else{
root.NProgress = factory();
}
})(this, function(){
console.log(`输出内容`);
})
千分位函数
Vue.filter('thousand', function (num, fixed) {
let n = Number(num)
if (isNaN(n)) return 0;
if (fixed && String(n).split('.').length === 2 && String(n).split('.')[1].length > fixed) {
n = num.toFixed(fixed)
}
const str = (n || 0).toString()
return str.indexOf('.') > -1 ? str.replace(/(\d)(?=(?:\d{3})+\.)/g, '$1,') : str.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
});
小技巧
1、获取arguments参数中的不同
function execute(name){
return [].slice.call(arguments, 1);
}
execute(1,2,3,4); // 返回 [2, 3, 4];
2、case语句
function showTest(type) {
switch(type) {
case "a": // type为a/b/c都执行console.log('ok')
case "b":
case "c":
console.log('ok');
break;
default:
console.log('error');
break;
}
}
兼容不支持的方法
1、 Object.create不支持的处理
Object.create = Object.create || function(obj){
var F = function(){};
F.prototype = obj;
return new F();
}
2、bind()
Function.prototype.bind = Function.prototype.bind || function(){
var self = this,
context = [].shift.call(arguments),
args = [].slice.call(arguments);
return function(){
return self.apply(context, [].concat.call(args, [].slice.call(arguments)))
}
}
| https://juejin.im/entry/58db95eaac502e0058f8472e
| http://www.iamaddy.net/2015/04/front-end-engineering/ // 前端的发展
国内查看评论需要代理~