体验ES6中类的秘密

class声明类的语法:

 <script>  // class cc { }  // console.log(typeof cc);  // let cc = class { };  // console.log(typeof cc);  // class User {  //  show() {  //   console.log('show');  //  }  // };  // let u = new User();  // u.show();  // function Lesson(title) {  //  this.title = title;  // }  // let l = new Lesson('html');  // console.log(l.title);  class Lesson {   constructor(title) {    this.title = title;   }   getTitle() {    console.log(this.title);   }  }  let l1 = new Lesson('l1');  console.log(l1.title);  l1.getTitle(); </script>

 

类的内部工作机制就是原型操作:

 

 <script>  class User {   // 属性初始值   constructor(name) {    this.name = name;   }   show() {    console.log('show');   }  }  console.dir(User);  console.log(User.prototype.constructor == User);  let u = new User('user');  // Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。  console.log(Object.getOwnPropertyNames(u));  console.log(Object.getOwnPropertyNames(User.prototype));  function Func(name) { this.name = name; }  Func.prototype.show = function () {   console.log('show');  }  console.dir(Func);  console.log(Func.prototype.constructor == Func);  let f = new Func('Func');  console.log(Object.getOwnPropertyNames(f));  console.log(Object.getOwnPropertyNames(Func.prototype)); </script>

 

对象属性的声明:

 <script>  class User {   site = 'www.baidu.com';   constructor(name) {    this.name = name;   }  }  let u = new User('user');  console.log(u.site); </script>

 

class声明的方法为什么不能遍历:

 <script>  // function Func(name) { this.name = name; }  // Func.prototype.show = function () { }  // console.log(JSON.stringify(Object.getOwnPropertyDescriptor(Func.prototype, 'show'), null, 2));  // // 可遍历  // let f = new Func('cyy');  // for (const key in f) { // 会去找原型  //  console.log(key);  // }  // for (const key in f) {  //  if (f.hasOwnProperty(key)) {  //   console.log(key);  //   console.log(f[key]);  //  }  // }  class User {   constructor(name) {    this.name = name;   }   show() {    console.log('show');   }  }  let u = new User('cyy');  console.log(JSON.stringify(Object.getOwnPropertyDescriptor(User.prototype, 'show'), null, 2));  // 方法不可遍历  for (const key in u) {   console.log(key);  } </script>

 

严格模式下运行:

 <script>  // 'use strict';  // function func() {  //  console.log(this);  // }  // func();  // function User() {  // }  // User.prototype.show = function () {  //  function func() {  //   console.log(this);//非严格模式下指向window  //  }  //  func();  // }  // let u = new User();  // u.show();  // 不管是在严格模式还是非严格模式下,都不会指向window  class User {   show() {    function func() {     console.log(this);//非严格模式下指向window    }    func();   }  }  let u = new User();  u.show(); </script>

 

静态属性使用:

 <script>  // 分配给构造函数的属性,称为静态属性  // function User(site) {  //  this.site = site;  // }  // User.site = 'cyy';  // let u = new User('user');  // console.log(u.site);// 非静态属性  // console.log(User.site);//静态属性  // 不能使用name,name会指向构造函数的名字  //静态属性在类上,而不是在实例化的对象上  class Request {   host = 'www.baidu.com';   static host2 = 'www.google.com';//静态属性   show(url) {    console.log(Request.host2 + url);   }  }  let r1 = new Request();  console.log(r1);  let r2 = new Request();  console.log(r2);  console.dir(Request);  r2.show('/taobao'); </script>

 

静态方法的实现原理:

 <script>  // function User() {  // }  // User.prototype.show = function () { }  // let u = new User();  // console.dir(u); //User的原型上有show,非静态方法  // User.show2 = function () { console.log(User == this); console.log(User.prototype.constructor == this); }//prototype.constructor指回构造函数  // console.dir(User);//静态方法:直接定义到函数上(对象原型上)  // // 函数也是对象,所以也可以用下面的写法  // User.__proto__.show3 = function () { }  // console.dir(User);  // User.show2();  // class Request {  //  show() {  //   console.log('show');  //  }  //  static show() {  //   console.log('static-show')  //  }  // }  // Request.__proto__.show2 = function () { } // 也是静态方法  // let r1 = new Request();  // r1.show();  // Request.show();//静态方法  // Request.show2();  // console.dir(r1);  // console.dir(Request);  class Member {   constructor(name, age) {    this.name = name;    this.age = age;   }   static create(...args) {    return new this(...args);   }  }  let m = Member.create('cyy', 18);  console.dir(m); </script>

 

静态属性练习之课程管理类:

 

 <script>  const lessons = [   { title: 'title1', click: 99 },   { title: 'title2', click: 13 },   { title: 'title3', click: 44 },  ];  class Lesson {   constructor(item) {    this.model = item;   }   // 访问器   get gclick() {    return this.model.click;   }   get gtitle() {    return this.model.title;   }   click() {    return this.model.click;   }   title() {    return this.model.title;   }   static createBatch(data) {    return data.map(item => new Lesson(item));   }   static maxClick(data) {    return data.sort((a, b) => b.click - a.click)[0]; // 访问器    // return data.sort((a, b) => b.click() - a.click())[0];   }   static totalClick(data) {    return data.reduce((t, c) => {     return t + c.gclick;    }, 0);   }  }  let res = Lesson.createBatch(lessons);  // console.log(res);  let res2 = Lesson.maxClick(res);  // console.log(res2);  // console.log(res2.title());  // console.log(res2.gtitle);//访问器  console.log(Lesson.totalClick(res)); </script>

 

在类中使用访问器:

 <script>  class Request {   constructor(url) {    this._url = url;   }   // setUrl(url) {   //  if (!/^https?:\/\//i.test(url)) {   //   throw new Error('地址错误~');   //  }   //  this.url = url;   // }   set url(url) {    if (!/^https?:\/\//i.test(url)) {     throw new Error('地址错误~');    }    this._url = url;//这里不能使用url,否则会死循环;   }   get url() {    return this._url;   }  }  let r = new Request('baidu.com');  // r.url = 'taobao.com';  // console.log(r);  // r.setUrl('google.com');  console.log(r.url); </script>

 

使用命名规则保护属性:

<script>  class User {   site = "baidu.com";   // 使用_代表被保护的属性   _age = 18;   constructor(name) {    this.name = name;   }   set age(age) {    if (age < 0 || age > 100) {     throw new Error('年龄不合法~')     ;    }    this._age = age;   }  }  let u = new User('user');  //开放属性可以在外部被更改  u.name = 'cyy';  u.site = 'taobao.com';  console.log(u);    u.age = 101;  console.log(u); </script>

 

使用Symbol定义protected属性:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  // const AGE = Symbol();  // class User {  //  site = "baidu.com";  //  // 使用_代表被保护的属性  //  // 实际上还是可以被修改的  //  // _age = 18;  //  [AGE] = 18;  //  constructor(name) {  //   this.name = name;  //  }  //  set age(age) {  //   if (age < 0 || age > 100) {  //    throw new Error('年龄不合法~')  //    ;  //   }  //   // this._age = age;  //   this[AGE] = age;  //  }  //  get age() {  //   return this[AGE];  //  }  // }  // let u = new User('user');  // //开放属性可以在外部被更改  // u.name = 'cyy';  // u.site = 'taobao.com';  // console.log(u);  // // u.age = 101;  // // console.log(u);  // u.age = 66;  // console.log(u);  //关于继承  // const AGE = Symbol();  // class Common {  //  [AGE] = 18;  //  set age(age) {  //   if (age < 0 || age > 100) {  //    throw new Error('年龄不合法~')  //    ;  //   }  //   this[AGE] = age;  //  }  //  get age() {  //   return this[AGE];  //  }  // }  // class User extends Common {  //  constructor(name) {  //   super();//必须在子类中使用super()调用父类的构造函数  //   this.name = name;  //  }  // }  // let u = new User('user');  // u.age = 66;  // console.log(u);  //多个受保护的属性  const protectes = Symbol();  class Common {   constructor() {    this[protectes] = {};    this[protectes].age = 18;   }   set age(age) {    if (age < 0 || age > 100) {     throw new Error('年龄不合法~')     ;    }    this[protectes].age = age;   }   get age() {    return this[protectes].age;   }  }  class User extends Common {   constructor(name) {    super();//必须在子类中使用super()调用父类的构造函数    this.name = name;   }  }  let u = new User('user');  u.age = 66;  console.log(u); </script></body></html>

 

使用WeakMap保护属性:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  // 继承的情况  // const host = new WeakMap();  // class Common {  //  constructor() {  //   host.set(this, 'baidu.com');  //  }  //  set host(url) {  //   if (!/^https?/i.test(url)) {  //    throw new Error('网址不合法~');  //   }  //   host.set(this, url);  //  }  //  get host() {  //   return host.get(this);  //  }  // }  // class User extends Common {  //  constructor() {  //   super();//调用父类的构造函数  //  }  // }  // let u = new User();  // console.log(u);  // console.log(u.host);  // 不继承的情况  // const host = new WeakMap();  // class User {  //  constructor() {  //   host.set(this, 'baidu.com');  //  }  //  set host(url) {  //   if (!/^https?/i.test(url)) {  //    throw new Error('网址不合法~');  //   }  //   host.set(this, url);  //  }  //  get host() {  //   return host.get(this);  //  }  // }  // let u = new User();  // console.log(u);  // console.log(u.host);  // 多个属性值的情况  const protects = new WeakMap();  class User {   constructor() {    protects.set(this, {     host: 'baidu.com',     name: 'cyy'    });   }   set host(url) {    if (!/^https?/i.test(url)) {     throw new Error('网址不合法~');    }    protects.set(this, { ...protects.get(this)['host'], url });   }   get host() {    return protects.get(this)['host'];   }   set name(name) {    protects.set(this, { ...protects.get(this)['name'], name });   }   get name() {    return protects.get(this)['name'];   }  }  let u = new User();  console.log(u);  console.log(u.host);  console.log(u.name); </script></body></html>

 

private私有属性使用:

<script>  //私有属性不可被继承,只能在当前类使用,子类不能使用  class Common {   #check() {    if (this.name.length < 5) {     throw new Error("名字长度不够呀~");    }    console.log(true);   }  }  class User extends Common {   constructor(name) {    this.name = name;    super();    this.#check();   }  }  let u = new User('cyy111');  console.log(u); </script>

 

class属性继承原理:

<script>  //构造函数中属性继承的原理  // function User(name) {  //  this.name = name;  // }  // function Admin(name) {  //  User.call(this, name);//继承属性  // }  // Admin.prototype = Object.create(User.prototype);//会自动继承方法  // Admin.prototype.show = function () {  // }  // console.dir(Admin);  //class使用super  class Common {   constructor(name) {    this.name = name;   }  }  class Admin extends Common {   constructor(name) {    super(name);   }  }  let a = new Admin('cyy');  console.log(a); </script>

 

类的方法继承原理:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  // function User() { }  // User.prototype.show = function () { console.log('user-show'); }  // function Admin() { }  // Admin.prototype = Object.create(User.prototype);//使用原型继承  // console.dir(Admin);  // let a = new Admin();  // a.show();  class Common {   show() { console.log('user-show'); }  }  class Admin extends Common { }  let a = new Admin('cyy');  a.show(); </script></body></html>

 

super原理分析:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  //super访问父类  class Common {   show() {    console.log(this.name);   }  }  class Admin extends Common {   constructor(name) {    super();    this.name = name;   }   show() {    super.show();//只调用父类的方法,this仍然指向当前类   }  }  let a = new Admin('cyy');  a.show();  // let user = {  //  name: 'user',  //  show() {  //   // console.log('user-show');  //   console.log(this.name);  //  }  // }  // let admin = {  //  name: 'admin',  //  __proto__: user,  //  show() {  //   //使用父类的方法  //   //this.__proto__.show();//this指向父类  //   this.__proto__.show.call(this);//this指向子类  //   console.log('admin-show');  //  }  // }  // console.log(admin);  // admin.show(); </script></body></html>

 

多重继承中super的魅力:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  //注意:super只能在简写的方法中使用,不能在function中使用!!!  // let common = {  //  show() {  //   console.log('common-show');  //  }  // }  // let user = {  //  name: 'user',  //  __proto__: common,  //  show() {  //   this.__proto__.show.call(this);//this指向admin,因此无法访问common中的方法  //   console.log(this.name);  //  }  // }  // let admin = {  //  name: 'admin',  //  __proto__: user,  //  show() {  //   this.__proto__.show.call(this);//this指向admin  //   console.log('admin-show');  //  }  // }  // console.log(admin);  // admin.show();  //使用super解决多重继承的问题  let common = {   show() {    console.log('common-show');   }  }  let user = {   name: 'user',   __proto__: common,   show() {    super.show(this);    console.log(this.name);   }  }  let admin = {   name: 'admin',   __proto__: user,   show() {    super.show(this);//调用父类的方法,this指向当前类   }  }  console.log(admin);  admin.show(); </script></body></html>

 

为什么子类constructor中执行super:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  // function User(name) {  //  this.name = name;  // }  // function Admin(...args) {  //  User.call(this, ...args);  //  // User.apply(this,args);  // }  // let a = new Admin('admin');  // console.log(a);  //子类没有constructor时,系统默认会使用super调用父类的constructor  // class User {  //  constructor(name) {  //   this.name = name;  //  }  // }  // class Admin extends User {  // }  // let a = new Admin('admin');  // console.log(a);  //子类中有constructor时,必须使用super用父类的constructor  class User {   constructor(name) {    this.name = name;   }  }  class Admin extends User {   constructor() {    super();   }  }  let a = new Admin('admin');  console.log(a); </script></body></html>

 

使用super访问父类方法:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  // class Controller {  //  total(data) {  //   return data.reduce((t, c) => t + c.price, 0);  //  }  // }  // class Lesson extends Controller {  //  constructor(data) {  //   super();  //   this.data = data;  //  }  //  result() {  //   return {  //    totalPrice: super.total(this.data)  //   };  //  }  // }  // let lessons = [  //  { name: 'name1', price: 48 },  //  { name: 'name2', price: 56 },  //  { name: 'name3', price: 33 },  // ];  // let l = new Lesson(lessons);  // console.log(l.result());  //多层继承  class Common {   total(data) {    return data.reduce((t, c) => t + c.price, 0);   }  }  class Controller extends Common {  }  class Lesson extends Controller {   constructor(data) {    super();    this.data = data;   }   result() {    return {     totalPrice: super.total(this.data)    };   }  }  let lessons = [   { name: 'name1', price: 48 },   { name: 'name2', price: 56 },   { name: 'name3', price: 33 },  ];  let l = new Lesson(lessons);  console.log(l.result()); </script></body></html>

 

方法的重写:

 

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  class Common {   total(data) {    return data.reduce((t, c) => t + c.price, 0);   }   getByKey(key) {    return this.data.filter(item => item.name.includes(key));   }  }  class Controller extends Common {  }  class Lesson extends Controller {   constructor(data) {    super();    this.data = data;   }   result() {    return {     totalPrice: super.total(this.data)    };   }   //方法重写   getByKey(key) {    return super.getByKey(key).map(item => item.name);   }  }  let lessons = [   { name: 'html', price: 48 },   { name: 'html5', price: 56 },   { name: 'css3', price: 33 },  ];  let l = new Lesson(lessons);  console.log(l.result());  console.log(l.getByKey('html')); </script></body></html>

 

静态继承原理:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  // function User() { }  // User.name = 'user';  // User.show = function () {  //  console.log('show');  // }  // function Admin() { }  // Admin.__proto__ = User;  // console.log(Admin.name);  // Admin.show();  //作为函数的prototype和作为对象的__proto__  class User {   static name = "user";   static show() {    console.log('show');   }  }  class Admin extends User {  }  console.dir(Admin); </script></body></html>

 

使用instanceof检测对象实现:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  // function User() { }  // function Admin() { }  // Admin.prototype = Object.create(User.prototype);  // let a = new Admin;  // console.log(a instanceof Admin);  // console.log(a instanceof User);  // console.log(a.__proto__ == Admin.prototype); // User  // console.log(Admin.prototype.__proto__ == User.prototype);  // console.log(a.__proto__.__proto__ == Admin.prototype.__proto__);  // console.log(a.__proto__.__proto__.__proto__ == Object.prototype);  // console.log(a.__proto__.__proto__.__proto__.__proto__); //null  // console.log(Object.prototype.__proto__ == null);  // function checkPrototype(obj, constructor) {  //  if (!obj.__proto__) return false;  //  if (obj.__proto__ == constructor.prototype) return true;  //  return checkPrototype(obj.__proto__, constructor);  // }  // console.log(checkPrototype(a, Admin));  // console.log(checkPrototype(a, User));  // console.log(checkPrototype(a, Object));  //作为函数的prototype和作为对象的__proto__  class User { }  class Admin extends User { }  let a = new Admin;  console.dir(a instanceof Admin);  console.dir(a instanceof User); </script></body></html>

 

isPrototypeOf检测继承关系:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  // let a = {}  // let b = {  //  __proto__: a //b的原型是a  // }  // console.log(a.isPrototypeOf(b));//检测a是不是b的原型  class Common { }  class Admin extends Common { }  let a = new Admin;  console.log(Admin.prototype.isPrototypeOf(a));  console.log(Common.prototype.isPrototypeOf(a));  console.log(Admin.isPrototypeOf(a));//必须是对象进行判断 </script></body></html>

 

内置类继承的原型实现:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  function Arr(...args) {   args.forEach(item => this.push(item));   console.log(this);   this.first = function () {    return this[0];   }   this.max = function () {    return this.sort((a, b) => b - a)[0];   }  }  Arr.prototype = Object.create(Array.prototype);  let a = new Arr(1, 44, 66, 88, 3);  console.log(a.first());  console.log(a.max()); </script></body></html>

 

使用继承增强内置类:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  class Arr extends Array {   //可省略   // constructor(...args) {   //  super(...args);   // }   first() {    return this[0];   }   max() {    return this.sort((a, b) => b - a)[0];   }   add(item) {    this.push(item);   }   remove(value) {    let pos = this.findIndex(item => item == value);    this.splice(pos, 1);   }  }  let a = new Arr(1, 44, 66, 88, 3);  // console.log(a.first());  // console.log(a.max());  a.push('cyy');  console.log(a);  a.remove(44);  console.log(a); </script></body></html>

 

mixin混合模式使用技巧:

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title></head><body> <script>  let Tool = {   max(key) {    return this.data.sort((a, b) => b[key] - a[key])[0];   }  };  let Arr = {   count(key) {    return this.data.reduce((t, c) => t + c[key], 0);   }  };  let lessons = [   { name: 'html', price: 100, click: 46 },   { name: 'css', price: 44, click: 75 },   { name: 'js', price: 22, click: 395 },  ];  class Lesson {   constructor(lessons) {    this.lessons = lessons;   }   get data() {    return this.lessons;   }  }  Object.assign(Lesson.prototype, Tool, Arr); //继承Tool类的方法  let l = new Lesson(lessons);  console.log(l.max('click'));  console.log(l.max('price'));  console.log(l.count('price'));  console.log(l.count('click')); </script></body></html>

 

灵活的动画处理类:

 

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>demo</title> <style>  .s1 {   width: 200px;   display: flex;   flex-direction: column;  }  dt {   background: orange;  }  dt:first-child {   border-radius: 5px 5px 0 0;  }  dd {   background: lightblue;   margin: 0;   height: 40px;   overflow: hidden;  }  dd:last-child {   border-radius: 0 0 5px 5px;  } </style></head><body> <div class="slide s1">  <dt>html</dt>  <dd>html-html</dd>  <dt>css</dt>  <dd>css-css</dd>  <dt>js</dt>  <dd>js-js</dd> </div> <script>  class Anima {   constructor(el) {    this.el = el;    this.defaultHeight = this.height;    this.isShow = true;    this.timeout = 5;   }   get height() {    return window.getComputedStyle(this.el).height.slice(0, -2) * 1;//去除后面的px,*1是转数值类型   }   set height(height) {    this.el.style.height = height + 'px';   }   hide(callback) {    this.isShow = false;    let id = setInterval(() => {     if (this.height <= 0) {      clearInterval(id);      callback && callback();      return;     }     this.height = this.height - 1;    }, this.timeout);   }   show(callback) {    this.isShow = true;    let id = setInterval(() => {     if (this.height >= this.defaultHeight) {      clearInterval(id);      callback && callback();      return;     }     this.height = this.height + 1;    }, this.timeout);   }  }  // let el = document.querySelector('.s1');  // let anim = new Anima(el);  // console.log(anim);  // anim.hide(() => {  //  console.log('隐藏结束~');  //  anim.show(() => {  //   console.log('展示结束~');  //  });  // });  class Slide {   constructor(el) {    this.el = document.querySelector(el);    this.links = this.el.querySelectorAll('dt');    this.panels = [...this.el.querySelectorAll('dd')].map(item => new Panel(item));    // console.log(this.panels);    this.bind();   }   bind() {    this.links.forEach((item, i) => {     item.addEventListener('click', () => {      // console.log(i);      // console.log('click');      this.action(i);     })    })   }   action(i) {    Panel.hideAll(Panel.filter(this.panels, i), () => {     this.panels[i].show();    });   }  }  class Panel extends Anima {   static num = 0;   static hideAll(items, callback) {    if (Panel.num > 0) return; //有动画正在执行,则不继续执行    items.forEach(item => {     Panel.num++;     item.hide(() => {      Panel.num--;     });    });    callback && callback();   }   static filter(items, i) {    return items.filter((item, index) => index != i);   }  }  let s = new Slide('.s1'); </script></body></html>









原文转载:http://www.shaoqun.com/a/493300.html

贝贝网:https://www.ikjzd.com/w/1321

心怡:https://www.ikjzd.com/w/1327

锦桥纺织网:https://www.ikjzd.com/w/2469


class声明类的语法:<script>//classcc{}//console.log(typeofcc);//letcc=class{};//console.log(typeofcc);//classUser{//show(){//console.log('show');//}//};//letu=newUser();//u.show();//functionLes
prime:prime
巴克莱银行:巴克莱银行
深圳特产是什么?哪里有深圳特产卖?:深圳特产是什么?哪里有深圳特产卖?
亚马逊listing关联销售,这些套路你都知道吗?:亚马逊listing关联销售,这些套路你都知道吗?
国庆去什刹海旅游有什么好玩的:国庆去什刹海旅游有什么好玩的

Comments

Popular posts from this blog

指纹浏览器定制开发全面助力企业安全与智能升级

跨境电商资讯:一文带你走进亚马逊19大海

利用 Google 购物广告促进销量的初学者指南